最新 追記

Matzにっき


2010年11月14日 [長年日記]

_ [Ruby] RubyConf 2010 キーノート(3)

で、最後に「Diversity(多様性)」である。

初日のDave Thomasのキーノートでも3つの重要なこととして、 Diversifyをあげていた。多様性は重要なのである。

とはいえ、多様性はいいことばかりでもない。 Rubyにおける多様性といえば、昨今数々登場している別実装である。

  • CRuby (1.9, 1.8)
  • JRuby
  • Rubinius
  • IronRuby
  • MacRuby
  • MagLev

などなど、多くのRuby実装がある。これら以外にも「Rubyっぽい言語」まで含めると 本当にいくつあるのか見当もつかない。

昔はPythonの人たちに「Ruby(とPerl)は複雑すぎて、別実装は登場しそうにない。 Pythonを見てみろ、CPythonとJytonとIronPythonがある」などと言われたものだが、 今や別実装の数ではRubyの方がしのいでいる。Pythonの方もPyPyとか新しいものも登場してるが。

が、一方、このような多様性にはコストがかかる。 まあ、プラットフォームの違うJRubyはおいておくとしても、 CRubyとRubiniusとMacRubyで分散しているリソースを集約すれば、 もっと早く言語(実装)が進歩するような気もしないでもない。

しかし、オープンソースプロジェクトでは結局はそれぞれの参加者がやりたいように関わって モチベーションを維持することの方がはるかに重要だ。

多様性は善で、コストは必要経費であるというのが私の認識である。

さて、多様性は善であるので、さらにそれを豊かにするために 私自ら新たな処理系を送り込もうと思う。

それは RiteVM であり、組み込みなど小規模なデバイス向けをターゲットとした処理系である。

現在のRubyは元々Unixをベースにして開発されたものであり、 UnixやPOSIX APIを提供しないような小さなデバイスや、 アプリケーションへの組み込みなどはあまり重視されてこなかった。

しかし、一方、組み込み分野などではデバイス性能の向上で ソフトウェアの比重が高まりつつあり、 実行速度やリアルタイム性がそれほど要求されない分野で Rubyのような「高級」な言語を使いたいという要求はそれなりにあるようだ。

そこで、以下のような処理系を新規に開発する

  • 小規模なRuby言語処理系
  • 機能はほぼRuby標準規格を満たす最小限。 さらにファイルI/Oなどは取り除く(後で追加可能)
  • 実装はLuaを意識
  • VM構造体を提供。グローバル変数を使わない
  • 機能はコンポーネントとして提供。必要に応じて外せる。 たとえばコンパイラを外してevalもなし、などが実現できる
  • ターゲットの要求に合わせてコンパイル時にさまざまに設定可能。 たとえば浮動小数点数をdoubleにするかfloatにするか、 Fixnumをintにするか、longにするか、long longにするか、など。 逆にいうと「どこでも同じように動く」は追求しない
  • 浮動小数点数はimmediate(shootout対策w)。
  • VMは32ビットワード命令、レジスタベース。命令セットもLuaに類似。
  • GCはレイテンシを重視。インクリメンタルアルゴリズムを採用。 世代別についても検討したい

このVM開発のプロジェクトコードネームは Rite と称することにする。 RiteVMの開発は、経済産業省 平成22年度「地域イノベーション創出研究開発事業」の一環として行われる。

これにより、たとえば

  • ゲームの組み込みスクリプト
  • デジタル家電のソフトウェア開発
  • 組み込み機器やロボットの非リアルタイム制御

などにRuby(のサブセット)が使えるようにする。

もちろん、今すぐにそうなるとは思っていないが、 今から準備すれば数年後には現実にできると考えている(ビジネス上の成功は別だけど)。

と、ぶちあげてしまったので、もう後に引けなくなったな。

FAQ

いつ Rite が使えるようになるの?
わかりません。が、上述の通り、経済産業省の事業なので事業が終了する2011年度末には なんらかの成果をあげないと、いろいろまずいことに...。
RiteVMはオープンソースになるの?
はい。MITライセンスを考えています。ただし、今回(とその周辺)の開発で ビジネスモデルを確立する必要があるので、あるいはGPL+商用ライセンスの MySQLモデルになるかもしれません。 いずれにせよ、オープンソースになることは期待して良いでしょう。
RiteVMが登場したらCRubyはお蔵入り?
そんなことはありません。Riteは分野限定の小規模実装ですから、 フル機能実装であるCRubyの代替にはならないでしょう。
C APIはどうなるの?
今までのCRubyのAPIとは異なるものになります。CRubyのAPIは非常に使いやすいけれども 組み込みにはあまり向かないからです。技術的には不可能ではなさそうですが、 互換レイヤーを導入する予定は当面ありません。
RiteVMはM17Nを提供しますか?
いいえ、コンパイル時にASCIIかUTF-8を選択してください。 エンコード変換機能も(標準では)提供しません。
native threadをサポートしますか?
いいえ、RiteVMそのものはスレッドをサポートしません。 native threadを活用したい時には各スレッドにVMを割り当ててください。 fiberはVMで提供するかもしれませんが、予定は未定です。
RiteVMはYARV/JRuby/Rubiniusより高い性能が出ますか?
たぶんそんなに性能は出ません。ただし、Floatの即値化とかのおかげで いくつかのベンチマークでは良い性能がでるかもしれません。
RiteVMの開発に貢献できますか?
オープンソース化されるまで待ってください。 githubで公開されると思います。gitの勉強しないとな
Riteって聞いたことあるんだけど
2003年のRubyConfキーノートでRuby 2.0の実装コードネームとして提案した名称です。 結局、新しいVMはYARVが採用されたわけですが、まさかこんな形で復活するとは。
まつもとさんはCRubyの開発から引退するんですか?
今でも十分貢献できてないんですが、引退するつもりはありません。 CRubyはRubyの第一実装であり続けますし、 私もRubyの設計者であり、コミュニティーのリーダーであり続けます。

2010年11月13日 [長年日記]

_ [Ruby] RubyConf 2010 キーノート(2)

前回に続いて 未来(≒Ruby 2.0)の話を。

今回、紹介した「未来」の機能は以下の通り。

  • Traits
  • Method Combination
  • Keyword arguments
  • Namespaces

今まで話してきたことじゃん、と思うでしょうが、その通り。 違いは

  • これらの機能が単なるアイディアではなく、どのように実装すべきかほぼ見えている
  • 実装した機能を突っ込む場所(trunk)が明確になっている

点です。特に後者は大きい。

Traits

Traitsの定義は

a trait is a collection of methods, used as a "simple conceptual model for structuring object oriented programs".

from Wikipedia (en)

ということで、モジュールとほぼ同じようなものです。 実際、今回導入するTraitsは言語要素の実体としてはモジュールを利用します。

ただ、モジュールの機能を取り込むのにincludeではない 別のやり方(mix)を導入することによって、includeが持ついくつかの問題を解消しよう というものです。includeの方が便利なこともあるので、includeもなくなりません。

includeの問題は

  • 名前の重複を検出できないこと
  • モジュールのinclude関係が後から変化した場合の一貫性のない挙動
  • メソッドを後から修飾する(wrapする)方法が提供されない

ことです。

擬似的な多重継承であるincludeは、 includeされたモジュールが継承ライン(ancestors)に含まれるようになります。 この時、状況によっては予測困難なことが発生します。

ひとつはincludeされた複数のモジュールで同名のメソッドが定義されていた場合、 その重複が意図されたもの(override)か、偶然か(conflict)か、 区別する手段がないところです(名称重複問題)。

もうひとつは、いくつかの状況で継承ラインに並ぶモジュールの順序が予測しがたい (ので、メソッド名の重複時にどれが優先になるのか直感的でない)ことです。

module American
  attr_accessor :address
end
module Japanese
  attr_accessor :address
end
class JapaneseAmerican
  include American
  include Japanese
end
JapaneseAmerican.new.address
# which address?
p JapaneseAmerican.ancestors
# => [JapaneseAmerican, Japanese, American, Object, Kernel]

この例ではaddressという属性(メソッド)がAmericanとJapaneseの間で 重複していますが、これが意図的な重複なのか偶然かは言語にはわかりません。 継承ラインの順にしたがってメソッドを呼び出すだけです。

実際にはJapaneseモジュールが優先されてそのaddressメソッドが呼ばれるのですが、 ひとめでそれが分かるのは、だいぶ「訓練されたRubyist」です。

現在のRubyでは、includeされた時、 「スーパークラスですでにそのモジュールがincludeされていた時には 二重にincludeしない」という挙動になっています*1。ですから、 スーパークラスでincludeされていることに気がつかなかった場合、 includeしても継承ラインのその場所にモジュールが登場しなかった ということが起こりえます。

それから、モジュールが既にincludeされてから、 そのモジュールに対してincludeを行った場合、 既に存在するクラスの継承ラインには新たにincludeされるようになったモジュールは含まれません。 つまり、includeのタイミングによって継承ラインへの反映のされ方が異なるわけです。 ちょっと気持ち悪いです。

これらを(ある程度)解決する手段がmixメソッドです。

mixメソッドをincludeの代わりに使うと、

  • 現在モジュールに定義されているメソッドを クラス/モジュールに注入する
  • mixされたモジュールは継承ラインに登場しない
  • メソッド名の重複は例外になる
  • 例外がイヤならモジュールを書き換える、 または重複したメソッドの名称を変更する
  • 定数を取り込むかどうかを指定できる。 デフォルトは取り込まない

という振舞いになります。これにより

  • 名称の重複はエラーになるので、見逃しがない
  • 名称変更ができるので、明示的に解消できる
  • あくまでも「現時点での状態の注入」なので、 継承ラインが変化した時の「おかしさ」がない。 問題は解決していないが、気分は良い(苦笑)

ということが実現できます。

たとえば以下のようなコードでは

module American
  attr_accessor :address
end
module Japanese
  attr_accessor :address
end
class JapaneseAmerican
  mix American
  mix Japanese  # => address conflict!
end

addressメソッドが重なっているからmixできません。 無事mixさせるためには名称衝突を明示的に回避します。

class JapaneseAmerican
  mix American, :address => :us_address
  mix Japanese, :address => :jp_address
end

これで、addressという名前による重複はなくなりました。

なぜ、includeにオプションをつけるのではなく、 新しいメソッドを導入して言語をより複雑にするかというと、 個人的にmixの挙動の方が望ましいと思っていて、 ユーザーをそちらに誘導するためには、より短い名前の方が望ましいと思ったからです。

Traitsを実現するmixメソッドの実装ですが、 RubyKaigiでこれを紹介したその日には中田さんが着手していて、 パッチは完成しているそうです。

ただ、各種プレゼンテーションでは説明しなかった以下の課題があり、 これらについては結論を出す必要があります。

  • mixされるモジュールが別のモジュールをincludeしていた場合にはどうなるか。 おそらくは例外になる。mixとincludeは混ぜるべきではない。
  • mixで別名を付けて問題解決、と読めるような言い方をしているが、 実際にはモジュール内部で名前を書き換える前のメソッドを読んでいる可能性がある。 それをどうするか。なにもしない(重複する方が悪い)とする考えもあるが、 それだとせっかく苦労してTraitsを導入しようとしているのが まったく無駄になるので、名前を書き換えたメソッド呼び出しを モジュールのメソッド定義実体から探し出してメソッドをコピーする という(Bertrand MayerのOOSCに記述されていたアイディア)を導入することを考える
  • インスタンス変数の名称重複を解決する手段がない。 これはサブクラスからは見えないインスタンス変数を導入し、 mix対象のクラスではそちらを使うこと推奨とするべきではないかと 考えています。1.9向けのパッチは既に書いてありますが、 プライベートなインスタンス変数の記法を @_fooをにするか、@__fooにするか、 はたまたまったく違うナニかを考えるのかが難しくて現状では放置されています。 mixが導入されたらより必要になるでしょうね。

Method Combination

RubyKaigiではmixの一部として導入する話をしていたMethod Combinationだが、 mixでいちいち「どのメソッドをラップするか」とか指定するのが以上にめんどくさいことに 後で気がつきました。ので、分離。

今回の案はprependというメソッドを導入すること。「include、mixに続いて またもうひとつ?」という声が聞こえてきそうだが、私もそう思います。でも必要なのよ。

prependはそのモジュールが提供する機能を、現在のクラス/モジュールの「前」に 追加する機能。

module Foo
  def foo
    p :before
    super
    p :after
  end
end
class Bar
  def foo
    p :foo
  end
  prepend Foo
end
Bar.new.foo # :before, :foo, :after

とように使う。prependしたモジュールFooで定義されたfooメソッドが、 prepend先のメソッドfooをラップしているのが分かるでしょうか。

prependメソッドは、RailsコミッタでもあるYehuda Katzの提案で、 これがあればRailsのalias_method_chainを撲滅できる、と息巻いていた。 私もそう思う。

具体的な実装はまだないんだけど、たぶんT_ICLASSのようなものを 継承チェーンに置いて、そっちを先に検索するようにするんじゃないかなあ。

Keyword Arguments

引数、特にオプショナル引数がどんな働きをするのか忘れる人は私だけじゃないと思います。 たとえば、 public_instance_methods メソッドはオプショナル引数を受け付けるのだけど、 それが「オプショナル引数を付けると、それが真であった時にスーパークラスのメソッドを含む」のか、 それとも逆かというのは私でもいつも忘れてしまいます。正解はfalseを付けた時に含まない。

これをたとえば

aClass.public_instance_methods(include_super: false)

と書けたら、ずっと覚えやすくなるというものです。

Rubyのキーワード引数は、1.9で追加されたシンボル記法のハッシュが 引数リストの末尾に付いているだけです。

2.0で新たに追加されたのは、メソッド定義側でこれを簡単に受け取れる記法です。

例としてはこんな感じ。

呼び出し側

1.step(by: 2, to: 20) do |i|
  p i
end

呼び出され側

def step(by: step, to: limit)
  ...
end

後、「**」で辞書形式で受けとるとか、ちょっとした機能追加もありますが、 基本的にはこれだけ。

Namespace

技術的な詳細などについては同じRubyConfで前田(修吾)くんが発表したスライドを見てもらった方が良いと思います。

Rubyではopen classといって既存のクラスの定義を書き換えちゃうことができる。 メソッドの追加も自由自在だ。このように既存のクラスに「パッチ」を当てちゃう技法のことを 「Monkey Patching」と呼ぶことも多い。

これは「ゲリラ・パッチング」→「ゴリラ・パッチング」→「モンキー・パッチング」と 変化して生まれた用語なんだって。 まあ、Rubyはクラスなんてものは変化するもんじゃないって「硬い」言語よりも 大きな自由を提供してることは確かだよね。 DHHは今回のRubyConfのキーノートで「今後はMonkey PatchingじゃなくてFreedom Patchingと呼ぼう」と 叫んでた。メル・ギブソンの『ブレーヴハート』を引用しつつ。「ふりーだーーむ」。

まあ、フリーダムなのは素晴らしいことなんだけど、影響力が大きすぎるというのもまた事実。 やろうと思えば整数のプラスメソッドを書き換えて、1+2 = 42 のような変更だってできちゃうから。 でも、大抵のプログラムは副作用でまともに動作しなくなるよね。

で、問題はこのような変更の影響の範囲がグローバル(プログラム全体)であることで、 仮にこのような修正をなんらかの「スコープ」に閉じ込めることができたなら、 もっと安全に、もっと安心して「フリーダム・パッチング」を活用できる、はず。

そのような「スコープ」のために、昔からClassboxとかSelector Namespaceとかが提案されてきた のですが、今回、前田くんが実装したのはSelector Namespaceの一種であるRefinment。

たとえば、以下のようなプログラムがあったとします。っていうか、あります。

class Integer
  def /(other)
    return quo(other)
  end
end
p 1/2 # => (1/2)

これは割り算演算子(/)を再定義して、整除ではなく結果を有理数にしようもので、 標準添付ライブラリの mathn の本質部分です。 しかし、整数の割り算の結果が整数であることを期待しているコードは当然存在するわけで、 そのようなコードは上のような変更で破綻する可能性があります。

そこで今回導入しようというのがrefinmentです(呼び名は変わるかもしれません)。 文法としては以下のようになります。

module MathN
  refine Integer do
    def /(other)
      return quo(other)
    end
  end
  p 1/2 # => (1/2)
end
p 1/2   # => 0

Refinementの単位としてはモジュールを使います。またモジュールです。大活躍ですね。

モジュールの中では既存のクラスをrefineできます。 refineの中で定義された修正はそのrefinment(ネームスペース)の中でだけ有効です。 ですから、MathNモジュールの中では 1/2 は有理数の (1/2) であり、 その外側では今まで通り整除になっています。有効範囲はレキシカルであり、 Refinmentはブロックの外側には影響を与えません。

Classboxとの違いは、そこを通じて呼び出された先(レキシカルスコープの外)に 「置き換え」が影響を与えるかで、いろいろ検討した結果、 多くのプログラミング言語がダイナミックスコープをあきらめたのと同様の理由で 「置き換え」はレキシカルになるべきだとの結論を出しました。

モジュールとして実現されたネームスペースを使うには usingメソッドを使います。 こんな感じ。

module Rationalize
  using MathN
  p 1/2 # => (1/2)
end
p 1/2 # => 0

これでRationalizeモジュールの中ではMathNが提供するRefinementが利用できます。

さらに、今までメソッドの中でメソッドをネストして定義した場合、 そのメソッドはクラスに直接定義されてあんまり意味ないじゃん、みたいな状態になっていたのですが、 今後はそのメソッドの範囲内でだけ有効なRefinementにネストの内側のメソッドが定義されるので、 完全にプライベートなメソッドとして使うことができます。

class Foo
   def foo
      def bar
        ...
      end
      bar # 呼べる
   end

   def quux
     bar  # 呼べない
   end
end

この変更はかなり大規模かつ複雑なものですが、前田くんのところでは実際に動作しています。 早く trunk に突っ込みたいものです。しかし、NaCl取締役の激務をこなしつつ、 こんなスーパーなパッチを作っちゃう前田くんに拍手。

まとめ

歴史編で見てきた通り、ずっと昔からキーワード引数などについて話してきましたが、 とうとう現実になりそうです。長かった。

*1  MacRubyでは違うらしい。Ruby 1.9でそのような変更をしたかったが、YARVが継承ラインに同じモジュールが2度登場しないことを前提にしていたため断念


2010年11月12日 [長年日記]

_ [Ruby] RubyConf 2010 キーノート(1)

New Orleansで開催されているRubyConf 2010に来ています(執筆時点では既に終了)。

で、今回のRubyConfはキーノートが3つもあるという豪華版でした。 ひとつは1日目最初のDave Thomasによるもの、 次は2日目最初のDavid Heinemeier Hanssenによるもの、 最後が2日目最後の私によるものです。

他のキーノートは、それぞれ感動的で素晴らしかったのですが、 その辺は他の方のレポートにお任せしようと思います。 そのうち、confreaksからビデオも公開されるだろうし。

で、今回は私のキーノートで発表した内容の紹介と その解説をしてみようと思います。

ちなみにスライドはSlideShareにアップしました。

今回のテーマは

  • History (歴史)
  • Future (未来)
  • Diversity (多様性)

でした。Matzにっきでは、これを3つに分けて紹介しようと思います。

今日はまず最初の「History」について。

RubyConfはもう今回で10回目になります。 最初は30人強で始まったRubyConfも、今回は800人を越える規模に成長しました。 っていうか、ここ数年は会場の都合などで500人規模で安定していたのですが、 あっという間にチケットが売り切れるありさまでした。昨年など24時間保たなかったようで、 いけるかな、などと悩んでいるともうダメという状況です。

今回は会場が広かったこともあって、チケットにもだいぶ余裕があったようです。

過去のRubyConfとそこでのキーノートを振り返ると、

2001 フロリダ州タンパ

記念すべき最初のRubyConfです。ACMのカンファレンス、OOPSLAの直前を狙って開催されました。 日本人は3名(私、高橋さん、青木さん)。この年は 911 の年でもあり、 また、フロリダは炭疽菌の騒ぎが起きた場所だったので、まわりに大変心配されました。 テレビのニュースではAnthrax(炭疽菌)という単語が繰り返し登場していました。

あと、フロリダでは父の古くからの知人のお宅にお邪魔したりして、 久しぶり(23年ぶり)の米国訪問は楽しい時間になりました。

この年のキーノートのタイトルは「Human-Oriented Programming in Ruby」で、 Rubyは人間にフォーカスしてるんだよ、みたいな話をしました。原点ですね。

2002 ワシントン州シアトル

2回目のRubyConfはSeattle.rbのお膝元シアトルで開催されました。 この時もOOPSLA直前開催です。 Seattle.rbの面々は、Aaron Pattersonはいなかったと思うけど、Eric HodelもRyan Davisも すでに参加していました。Dan SugalskiがParrotの話をしたのもこの回だったような。

キーノートは「Be Minor, Be Cool」です。 クールなことはマイノリティからくる。 我々は(まだ)あまり知られていないかもしれないけどクールなことをしようじゃないか という呼びかけです。

2003 テキサス州オースチン

この時も(この回まで)OOPSLA直前だったような気がします。 思い出されるのは、RubyConf前に Texus A&M Universityを訪問して Bjarne Stroustrupと時間を過ごしたことです。 個人的に私が C++ についてどう思っているか、ということは置いておいて Bjarneは素晴らしい人格と素晴らしい頭脳の持ち主です。とっても親切でした。

この時のキーノートは「Visions for the Future, or How Ruby Sucks」です。 Ruby 2.0がどうなるか、なんて話をこんなに前からしてたんですね。 M17Nや鬼車、あと定数の検索順序のようなその後1.9で実現されたものもあれば、 ローカル変数のスコープのように、悩んだ挙句結局変更しないことにしたものもあり、 キーワード引数やSelector Namespaceのように、やっと実現のめどがついたものなどが もう7年も前にそうとう詳しく述べられています。

ここで紹介されたアイディアの中にはprivate instance variable(サブクラスから見えないインスタンス変数)のような、秀逸ながら文法が決まらずお蔵入りのものもありました。手元にはパッチもあるんですよねえ。

2004 バージニア州シャンティ

Chantillyは「シャンティ」と発音するようですね。

実はこの回は出席できていないんです。ちょうど末娘の誕生のころで、 さすがに臨月の妻をおいてアメリカへ行くのははばかられました。 この回は、笹田くんがYARVの発表をしています。 非常に好評だったと聞いています。キーノートはObjecive-Cの作者 Brad Cox が してくださったそうです。もっとも Objective-C については全く言及しなかったようですが。

2005 カリフォルニア州サンディエゴ

サンディエゴはあたたかくていいところでした。 ホテルもおしゃれでした。向こうでは、偶然知人のお父さんに会って ディナーをご馳走になったりしました。

この年のキーノートは 「Visions for the Future, or Wild and Weird Ideas」で、 やっぱり未来に向けての「ワイルドなアイディア」について語っています。 keyword arguments, eval, lambda, annotations, traits, namespace, method combination, multilingualization などについて語っていますが、 こんなに昔からいろいろ考えていたのねと感心するべきか、 こんなに時間がたってもぜんぜん手付かずのものがこんなにあるのねとあきれるべきか。

後者なんでしょうね。

2006 コロラド州デンバー

なんかデンバーとっても寒かったです。会期中には雪が降ったし。 ホテルの駐車場でリスがうろうろしていたのが面白かったです。

この時のキーノートは「The Return of the Bikeshed or Nuclear Plant in the Backyard」 というテーマでした。言語設計はとっても楽しいからみんなも参加しようよ、 というような感じです。その後、いろんな人が参加してくれるかなと思ったのですが、 実際にはいまいち盛り上がりませんでした。やっぱ言語設計は敷居が高いんでしょうか。

2007 ノースカロライナ州シャーロット

東海岸です。2004年のバージニアを逃した私には、はじめての東海岸らしい東海岸です。 分類上は2001年のフロリダも東海岸ですが、東というよりも南という印象が強いですね。

この年は「Language Matters or Not」。プログラミングにおいて言語の果たす役割は大きい、 とかなんとか。あと恒例の新機能紹介も入ってます。 その後激論を呼び起こした「->(Stabby Lambda)」が公表されたのもこの時でしたね。 あの時はむしろ反対が多かったStabby Lambdaですが、みんなあきらめたのか 最近では文句をいう人はもうあまりいませんね。計算通り。

2008 フロリダ州オーランド

2度目のフロリダ州です。ディズニーワールドなどリゾート地の印象が強いオーランドですが、 ホテルはかなり世間と隔絶したところにあったので、集中できました。 ちょうど大統領選挙の激戦の最中だったので、「どっちを支持する」とか 真剣に聞かれて困りました。ところでプログラミング関係はリベラルで民主党支持の人が多いようですね。

この年のキーノートは「Reasons behind Ruby」です。 わりと原点に戻ったキーノートですね。Rails世代が増えてきてることを意識したキーノートです。 技術色が薄いので、あんまりおもしろくないと思った人も多かったかもしれません。

2009 カリフォルニア州サンフランシスコ

2009年RubyConfの会場は、シリコンバレーにほど近い、IT業界の中心地サンフランシスコです。 なんかRubyConfの前の日にInfoQが開催するQConでも セッションを持ったりして忙しかった覚えがあります。

この年のキーノートは「The 0.8 True Language」です。 聞き慣れない表現ですが、指輪物語の「One True Ring」を意識しています。 すべてに向いた「One True Language」はなくとも パレートの法則に従い80%をカバーする言語はありえるんじゃないか、 Rubyはそれに近いんじゃないか、とかいうような話です。

2010 ルイジアナ州ニューオーリンズ

今年はニューオーリンズです。実はニューオーリンズは松江市の姉妹都市なんですね。 だからどうということはありませんが、音楽が鳴り響く明るい感じの街で、 食べ物がおいしいのが素晴らしいです。カンファレンスご飯もおいしくて 参加者達がびっくりしていました(大抵は、食べれるけどそんなにおいしくない)。

そして今年のキーノートのテーマは「Future and Diversity」です。

続きは別エントリで。まず Future (≒Ruby 2.0) について、 そしてその次のエントリで Diversity (多様性) について解説します。


2010年06月24日 [長年日記]

_ 上海

着いた。ホテルにチェックイン。ネットも使える。

でも、アクセスできないサイトがぼろぼろあって泣ける。 Twitterも使えない。

メールは普通に使えるみたい。

_ 買い物

上海の電気街(っていうか巨大なラジオ会館)のようなところで買い物。

携帯電話がカオス。Suny EricssonとかNCKIAとかいっぱいある。 あと、大量のiPhone電話とか。 Androidで動くiPad風タブレットもあった。1500元。なぜかメニューが全部日本語。

帰りに容量500Gと書いてあるUSBメモリ(Sonyブランド)があったので、 値段を聞いたら100元(約1500円)だとか。 安すぎて、絶対にその容量はなさそうだけど、 話のタネにと思って購入。ねぎったら80元になった(!)。

ホテルに戻ってPCにつないだら、本当に524Gと表示された。びっくり。 この容量がぜんぶ使えるんだろうか。いろいろ試してみないと。

_ 大容量USBメモリ

やっぱ、使えなさそう。

  1. すごく遅い。書き込みで1.7MB/sくらい。PC内蔵のSATAが35MB/sくらい出てることを考えるとすごく遅い。
  2. エラーが多い。ファイルを書き込んだら壊れてた。再度書いたら大丈夫だったファイルもあった。
  3. エラーがすごく多いww 1GBくらいのファイルに複数回md5sumをかけると、5分以上かけて計算して、そのたびにMD5値が異なる。

しかし、こんな使い物にならないものを、誰がなんのために作るのか。

ネタになったからいいけど。


2010年06月18日 [長年日記]

_ [Ruby] Ruby2.0の新機能(かもしれないもの)(4) keyword arguments

注意。このエントリはRuby 2.0に入るかもしれない機能について述べていますが、本機能が本当に2.0に採用されるかどうかは、未定です。

「まだあるのか」とか思われそうだけど、まだあるんです。

今度は長年採用すると言いつつ、ほったらかしの最右翼、キーワード引数である。 調べたら、キーワード引数については、2003年のRubyConfではすでに話題にしている。 どんだけ前から口にしてたんだ。「やるやる詐欺」だな(苦笑)。

その時の仕様はこんな感じ。

def foo(a, b: 42, **keys)
   p [a,b,keys]
end
foo(1)             # => [1,42,{}]
foo(2, b: 5)       # => [2,5,{}]
foo(3, b: 4, c: 6) # => [3,4,{:c=>6}]

まあ、そんなに悪くない。基本的にはこの線を踏襲しようと思う。 文法としては、ブロック引数の直前に

keyword: value,..., **keys

というキーワード引数を置くことができる、というもの。 Pythonと違ってキーワード引数は明示的に指定しなければならない。 通常の引数名が勝手にキーワードになったりはしない。

問題はrest引数と組み合わさった時。

def baz(*rest, a:4, b:0, **keys)
  ...
end

として、以下の呼び出しを行ったらどうなるか。

baz()           # rest=[],a=4,b=0,keys={}
baz(1)          # rest=[1],a=4,b=0,keys={}
baz(a:1)        # rest=[],a=1,b=0,keys={}
baz(a:1,b:2)    # rest=[],a=1,b=2,keys={}
baz(1,2,b:2)    # rest=[1,2],a=4,b=2,keys={}
baz(c:2)        # rest=[],a=4,b=0,keys={c:2}

つまり、以下のルールに従う。

  • 引数が0の場合、キーワード指定は{}とみなす。
  • 引数が1個以上の時、末尾の引数がHashでなければ、キーワード指定は{}とみなす。
  • 引数が1個以上で、末尾がHashであればそれがキーワード指定。引数リストから取り除く※
    • キーワード指定に、キーワード引数があればそれを取り除き、キーワードと同じ名前の変数に代入
    • キーワード指定にキーワードが含まれていなければ、デフォルト値を代入
    • 「**keys」が指定されていない時に、キーワード指定がキーワード引数として定義されていないキーを含む時には、ArgumentError例外

なお、※の部分はRubyConf 2005のキーノートで紹介したものと動作が違う。

この仕様ではキーワード指定はあくまでも通常引数の一部なので、 通常引数の引渡の時には *rest で受けて、 foo(*rest) と呼び出せばよい(はず)。

呼び出し側のキーワード引数は結局は引数リスト末尾のハッシュに過ぎないので、 呼び出し側では foo(**keys) のような文法は(本来は)不要。 ただし、対称性と型チェックのために採用する可能性は、なきにしもあらず(あんまり積極的ではない)。


最新 追記