Skip to content

Instantly share code, notes, and snippets.

@frsyuki
Last active December 14, 2015 03:19
Show Gist options
  • Save frsyuki/5019759 to your computer and use it in GitHub Desktop.
Save frsyuki/5019759 to your computer and use it in GitHub Desktop.

msgpackの倉曎案に぀いお-3

抂芁

  • 珟行のRaw型をString型ずしお読み替える。
    • 珟行の FixRaw, raw 16, raw 32 は、FixString, string 16, string 32 になる
  • Binary型を新蚭する。
  • バむト列はBinary型で保存する。そうでなければString型で保存する。

背景

文字列ずバむナリの区別が曖昧な蚀語が存圚する。䟋えば

  • 文字列ずバむト列を区別する型がそもそも無い蚀語PHP, C++, Erlang, OCaml
  • 文字列を衚すためにフラグ等の付加情報が䜿われるが、文字列なのに付加情報が付䞎されおいないケヌスが䞀般的に存圚する蚀語Ruby, Perl, Python 2

これらの蚀語を weak-string languages ず呌ぶ。

䞀方で、区別が明確な dynamically-typed languages も存圚するJavaScript、Objective-C、Python 3。たた、区別が明確な statically-typed languages が存圚するJava、C#、Scala。これらの蚀語を strong-string languages ず呌ぶ。

strong-string and dynamically-typed languages が受信者ずなる オブゞェクトのやりずりでは、文字列ずしお送信/保存したデヌタを文字列ずしお、バむト列ずしお送信/保存したバむト列をバむト列ずしお、透過的に埩元したいずいう芁求が存圚する。※この芁求は、その他の組み合わせの通信では存圚しない

䞀方で、weak-string languages では、すべおの文字列に察しお「これは文字列である」ずマヌカを付䞎する、あるいはすべおのバむト列に「これはバむト列である」ずいうマヌカを付䞎する䜜業は手間がかかる。埓っおこれらの蚀語で曞かれたプログラムで、文字列ずバむト列が明確に区別できるこずを期埅するこずは珟実的ではない。

そこで、次のメリットを同時に満たす倉曎を提案する

  • strong-string languages 同士の通信においおは、文字列を文字列ずしお、バむト列をバむト列ずしお透過的に埩元できるようにする
  • weak-string languages ず strong-string languages が混圚した堎合のデヌタ亀換では
    • weak-string languages においおすべおのバむト列にマヌカを付ける䜜業を行えば、strong-string languages で透過的に型を埩元できるようにする
    • すべおの文字列ではなくすべおのバむト列にマヌカを付けるのは、バむト列の方が文字列より数が少なく、その䜜業の方が簡単だずいう仮定に基づいおいる
    • そうでなくおも、strong-string languages 偎のアプリケヌションで適切な実装を行えば、透過的ではないがデヌタ亀換が行えるようにする
  • weak-string languages 同士の通信では、既存のmsgpackずの互換性を維持する

型システムの倉曎

  • Binary: バむト列
  • String: UTF-8で゚ンコヌドされた文字列
    • UTF-8ずしおinvalidなバむトシヌケンスを含む文字列が保存されおいるこずもある。この理由は次の3぀
      • Unicodeは、その正しい取り扱いをmsgpackの党蚀語の実装にさせるには、耇雑すぎるため
      • シリアラむズ時にvalidateを行うず性胜にむンパクトがあるためstrong-string languages であっおも、UTF-8ずしおinvalidなバむトシヌケンスを含む文字列オブゞェクトを簡単に䜜れる蚀語が存圚するこずに泚意䟋:Python2
      • weak-string languages で曞かれたプログラムでは、文字列ずバむト列が明確に区別できるこずを期埅するこずは珟実的ではなく、結果ずしおバむト列がStringずしお扱われるこずがあるため
    • invalidなバむトシヌケンスを含む文字列を怜出した堎合の動䜜は、実装に䟝存する
      • ただし、invalidなバむトシヌケンスを含む文字列をどのように取り扱うかは、アプリケヌションが決定するべき仕事である

UTF-8ずしおinvalidなバむトシヌケンスを含むStringを受け取った堎合の動䜜は実装に䟝存する。䟋倖を発生させお匟く実装を行っおも良いし、その堎合に限りバむト列型を返すずいった実装でも良い。しかし、UTF-8ずしおinvalidなバむトシヌケンスを含むString型オブゞェクトが保存されおいたずしおも、アプリケヌションが望めば元のバむト列を取り出せるようにする手段も提䟛するこずが、匷く掚奚されるSHOULD or MUST。

フォヌマットの倉曎

0xa0-0xbf FixString (0bytes - 31bytes String type)  // changed

0xd5 binary 8 (0bytes - 255bytes Raw type)  // new
0xd6 binary 16 (256bytes - 65535bytes Raw type)  // new
0xd7 binary 32 (65536bytes - 4294967295bytes Raw type)  // new

0xd8 reserved

0xd9 string 8 (32bytes - 255bytes String type)  // new
0xda string 16 (256bytes - 65535bytes String type)  // changed from raw 16
0xdb string 32 (65536bytes - 4294967295bytes String type)  // changed from raw 32

strong-string and dynamically-typed languages における実装のガむドラむン

  • シリアラむザ

    • バむト列はBinary型ずしお保存する
    • 文字列はString型ずしお保存する
    • ただし、既存の実装ずの互換性を維持するために、バむト列もString型ずしお保存するオプションを実装しおも良い
  • デシリアラむザ

    • String型たたはBinary型をデシリアラむズしたら、それず分かるオブゞェクトを返す
    • String型にUTF-8ずしおinvalidなバむトシヌケンスが含たれおいた堎合に、アプリケヌションがそれらをハンドリングできるようにする機胜を提䟛するべきであるSHOULD
    • この実装方法は特に芏定しない。次のような方法が考えられる
      • invalidなバむトシヌケンスを発芋したら、そのオリゞナルのバむト列をフィヌルドに持぀オブゞェクトのむンスタンスを返す
      • invalidなバむトシヌケンスを含むこずができる文字列クラスを組み蟌み型ずは別に䜜成し、invalidなバむトシヌケンスが含たれるか吊かに関わらず、垞にそれを返すモヌドを実装する
      • invalidなバむトシヌケンスを発芋したら指定されおいたコヌルバック関数を呌び出し、その関数の返倀を返す

weak-string languages における実装のガむドラむン

  • シリアラむザ
    • バむト列か文字列かが自明でなければ、String型ずしお保存する
    • UTF-8のvalidationは行わなくおよい。String型はUTF-8ずしおinvalidなバむトシヌケンスを蚱容する
    • ナヌザヌが明瀺的に「これはバむト列だ」ずヒントを蚭定したオブゞェクトを受け取った堎合、それはBinary型ずしお保存するべきであるSHOULD
  • デシリアラむザ
    • String型のvalidationを行うべきではないSHOULD NOT
      • なぜなら、アプリケヌションがinvalidなバむトシヌケンスを含むStringの扱いを決めるべきだから
    • ただし、オプションを有効にすればString型でvalidationを機胜を実装をしおもよいMAY
    • Binary型を受け取った堎合、䜕らかのフラグが立ったString型ずは区別できる情報を含むオブゞェクトを返すオプションを実装しおも良いMAY
      • この挙動は、MessagePackを入力ずしお、MessagePackを出力するような、䞭間凊理を行うツヌルで、出力先でも型情報を維持しなければならないケヌスで必芁になる
      • この機胜が必芁なケヌスは、皀である
      • 実装の方法には、䟋えばPHPにおいおは、特定のオプションがonであったら、Binary型を受け取った堎合に、バむト列をフィヌルドずしお所有するMessagePackBinaryクラスのむンスタンスを返す方法ある

既存の実装の互換性に぀いお

  • マむナヌバヌゞョンアップで、新蚭されるBinary型をバむト列ずしお返す実装をリリヌスする
    • この時点で、新しい゚ンコヌダずの互換性が達成される
  • メゞャヌバヌゞョンアップで、バむト列を新蚭Binary型でシリアラむズする実装をリリヌスする
    • 同時に、区別が厳栌な環境の゚ンコヌダにおいお、バむト列もStringずしお保存するオプションを提䟛する
      • これは、新しい゚ンコヌダに切り替えた堎合でも、曞き出されるバむト列が倉化しないようにするために存圚する
      • 既存の実装ず互換性を維持するには、メゞャヌバヌゞョンアップするず同時に、このオプションをONにする
    • たた、゜ヌスコヌドレベルの互換性を維持するため、String型ずBinary型の䞡方をバむト列ずしお返すモヌドを提䟛する

募集䞭のアむディア

「甚語」で觊れられおいる蚀語の皮類を増やしたい。コメント求む。

この倉曎埌のMessagePackの呌び方。

  • 案1珟行の仕様をMessagePack 0.9 ず呌び、新しい仕様を MessagePack 1.0 ず呌ぶ
  • 案2珟行の仕様をMessagePack 1.0 ず呌び、新しい仕様を MessagePack 1.1 ず呌ぶ
@methane
Copy link

methane commented Feb 23, 2013

闇の軍団にボコられないために、C++を区別がない蚀語に列挙するのを止めるか、C++99 ず曞くのはどうでしょう(C++11 では u8"I'm a UTF-8 string." は UTF-8)

Invalid な utf-8 を䜜る可胜性がある蚀語に Python 2 を挙げるのも誀解を招くず思いたす。
str あるいはその alias の bytes は非UTF-8かもしれないのでそのたた String に栌玍するず
InvalidなUTF-8を䜜りたすが、これを文字列型ずしお分類するず、 str ず bytes が同䞀になり
「weak-string language」になりたす。
(Python 2 は weak-string ずしおも strong-string ずしおも利甚可胜な、少し特殊な蚀語です)

Invalid な utf-8 を認める理由に、珟行の msgpack には区別が無かったためずいうのも远蚘するず良いず思いたす。

@methane
Copy link

methane commented Feb 23, 2013

MessagePackのバヌゞョンは、珟行を 1.0, 新しいのを 2.0 ず呌ぶのが良いず思いたす。

これは明らかにメゞャヌバヌゞョンアップであるのず、ラむブラリによっおは互換性を重芖するモヌドず
新しい仕様に準拠するモヌドでクラス名や関数名を倉えたい堎合があり、 MessagePack11 だず 11 なのか 1.1
なのかわからないからです。

@kazuho
Copy link

kazuho commented Feb 23, 2013

はげしく重箱の炭ですが

@methane

闇の軍団にボコられないために、C++を区別がない蚀語に列挙するのを止めるか、C++99 ず曞くのはどうでしょう

C/C++においお、文字列ずバむナリの区別ができるかどうかは、芏栌のバヌゞョンに䟝存するのでなく文字コヌドずしおcharを䜿っおいる区別ができないか、wchar_t,uint16_t,uint32_t等を䜿っおいる区別ができるかに䟝存する問題だず思いたす。
たずえばCでもUTF-16を文字列型ず䜿っおコヌドを曞く、ずいうケヌスはWindowsだずありうるず思いたす

よっお、C/C++は、区別ができないグルヌプに入れ぀぀泚蚘するのがベストな遞択かず思いたす。

@methane
Copy link

methane commented Feb 23, 2013

あヌ、リテラルがあるだけで、それを刀断できる型を䜿うかどうかは別の話ですね。

@kenn
Copy link

kenn commented Feb 23, 2013

様々な懞念点が払拭されおいおStringの定矩も簡朔になり、玠晎らしいず思いたす

バヌゞョンに関しおは、ラむバルずなるJSONが http://www.json.org/fatfree.html で

JSON has no version number. No revisions to the JSON grammar are anticipated. If something has a 1.0, it will inevitably get a 1.1 and a 2.0, and everything is crap until it is 3.0. JSON is very stable.

ずいう哲孊を衚明しおおり、1.1だろうが2.0だろうがバヌゞョン぀けた時点で負け的な感じはありたす。

今回の仕様がvery stableであるず確信が持おるのであれば、、、埮劙なずころではありたすが「バむナリフォヌマットにおけるstringの扱い」ずいう最難関を乗り越えた印象はあるので、今埌の倉曎はもうないか、あっおも今回以䞊に倧きな倉曎はもう二床ずなさそうな気はするので、

  • 今回のものを䟿宜䞊「final」ずし、バヌゞョン番号はなし。100%の埌方互換性ず、䜿い方によっおはstringに確信犯的にバむナリを入れる運甚をくずさないこずで100%の前方互換も達成可胜。
    • 実装偎では、むしろ埌方互換モヌドをMessagePackCompatやMessagePackLegacyなどず名付ける
    • 既存の実装者のなかでバヌゞョンなしにこのような倉曎をするこずに䞍満をおがえる人もいるかもしれないが、長期的にはmsgpackが普及・成功しおくれるこずを願っおいるはずなので、ぐっずこらえお協力しおくれるはず、ず信じたい
  • やはりどうしおもバヌゞョン番号がないず䞍䟿ずいうこずであれば、0.9 -> 1.0を掚したす
    • IETFなどに持っおいくずきには、バヌゞョンなしが理想、あるいは1.0でいくのが今回の経緯を知らない人たちを巻き蟌む䞊ではもっずも䞍安をあたえず匷力

@kazuho
Copy link

kazuho commented Feb 23, 2013

@kenn

実装偎では、むしろ埌方互換モヌドをMessagePackCompatやMessagePackLegacyなどず名付ける

新しいものに゜ヌスコヌドレベルで MessagePack ずいう名前を割り圓おおしたうず、゜ヌスコヌドレベルでの互換性を保ちにくいずいうのが問題になりたす。

泚: Perlのモゞュヌルの名前空間はグロヌバル、぀たり、党モゞュヌルが単䞀の名前空間にぶら䞋がりたす

珟行の Perl 実装は以䞋のような感じです。

# hidekさんにhappy birthdayずいうメッセヌゞを送る
my $mp = Data::MessagePack->new;
my $packed => $mp->pack({
    to             => 'hidek',
    message => 'happy birthday',
});

このコヌドの゜ヌス互換性を砎壊せずに新フォヌマットに察応する方法ずしお Perl 界隈で「通垞」ずられる方法は以䞋のいずれかでしょう。

# バヌゞョン番号をモゞュヌル名に入れる (Data::MessagePack2 は Data::MessagePack ず䞀䜓ずしお配垃可胜)
my $mp = Data::MessagePack2->new;
# バヌゞョン番号をコンストラクタの匕数で指定する
my $mp = Data::MessagePack->new(VERSION => 2);

新旧぀のフォヌマットが、いずれも "MessagePack" ずいう名前で参照されるように Perl でできる唯䞀の方法は、"MessagePack" ずいうモゞュヌルが属する名前空間を倉える方法です。以䞋の䟋は、"Data::MessagePack" ずいう名前で珟行方匏のcodecを参照できるようにし぀぀、"MessagePack" ずいう新方匏を実装したモゞュヌル名をトップレベルに远加するこずで問題を回避しおいたす。名前空間がたたがっおも新旧の䞡モゞュヌルを䞀䜓ずしお配垃するこずはできたす。たた、䞡方のドキュメントでお互いに蚀及しおおけば、「ドキュメントを読めばどっちがどっちを指しおるのか分かる」ずいうレベルにはなりたす

my $mp = Data::MessagePack->new; # これは珟行圢匏
my $mp = MessagePack->new; # これは新圢匏

もし、

やはりどうしおもバヌゞョン番号がないず䞍䟿ずいうこずであれば、0.9 -> 1.0を掚したす

ずいうこずにする぀たり「今たでのが development version だったんだよ」ず @frsyuki さんがいうこずになるのであれば、䞊のように名前空間を移動するのがベストな察応になるかずは思いたす。

だが、これは、MessagePack を知らない他のモゞュヌルの開発者たちからは「驚き」をもっお受け止められるでしょう。

@methane
Copy link

methane commented Feb 24, 2013

既存の実装ずの互換性のためには、 binary だけでなく string8 も䜿わない (埓来の raw だけを䜿う) 必芁がある事を
明蚘するべきだず思いたす。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment