9

変数定義に関するルビーの奇妙な動作に出くわしました(途中でドーナツの箱を失いました):

irb(main):001:0> if false
irb(main):002:1>   a = 1
irb(main):003:1> end
=> nil
irb(main):005:0> a.nil?
=> true
irb(main):006:0> b.nil?
NameError: undefined local variable or method `b' for main:Object
    from (irb):6
    from /Users/jlh/.rbenv/versions/2.1.5/bin/irb:11:in `<main>'

なぜa.nil?投げていないのundefined local variableですか?たとえば、Python を見てみましょう (インタープリター言語と比較したかっただけです)。

>>> if False:
...     a = 1
... 
>>> print a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

コンパイルされた言語では、これはコンパイルさえしません。

  • これは、そのコードを実行していなくても、Ruby がその変数への参照を保持しているということですか?
  • もしそうなら、ifs/else は変数定義のためにどのくらい深く考えられますか?

これが Ruby で期待される動作だとは本当に信じられません。これは irb 固有のものではなく、ruby/rails コード ブロックで実行しても同じ結果が得られます。

4

2 に答える 2

5

Ruby では、ローカル変数の参照と、引数リストなしで暗黙の受信者に送信されるメッセージとの間にあいまいさがあります。つまり

foo

「ローカル変数を逆参照する」または「引数なしでメッセージfooを送信する」のいずれかを意味しselfます。つまり、次のいずれかと同等です。

binding.local_variable_get(:foo)

また

self.foo()
# or
public_send(:foo)

このあいまいさは解析時に解決されます。パーサーが への割り当てに遭遇するfooと、その時点からfoo、割り当てが実際に実行されるかどうかに関係なく、ローカル変数として扱われます。(結局のところ、これはパーサーが静的に判断できないものです。考えてみてif rand > 0.5 then foo = 42 endください。)

コンパイルされた言語では、これはコンパイルさえしません。

コンパイルされた言語のようなものはありません。コンパイルと解釈は、言語ではなく、コンパイラまたはインタープリターの特性です (当たり前!)。言語はコンパイルも解釈もされません。彼らはただです

すべての言語はコンパイラーで実装でき、すべての言語はインタープリターで実装できます。ほとんどの言語には、コンパイルされた実装と解釈された実装の両方があります (たとえば、C にはコンパイラである GCC と Clang、およびインタープリタである Cint と Cling があり、Haskell にはコンパイラである GHC とインタープリタである Hugs があります)。

多くの最新の言語実装では、異なるフェーズ (たとえば、YARV と MRuby が Ruby ソースコードを内部バイトコードにコンパイルし、次にそのバイトコードを解釈する) または混合モード エンジン (たとえば、HotSpot JVM は解釈とコンパイルの両方を行う) のいずれかで、同じ実装に両方を持っています。 JVM バイトコード、どちらがより理にかなっているのかに応じて)、または両方 (たとえば、Rubinius は最初のフェーズで Ruby ソースコードを Rubinius バイトコードにコンパイルし、次にそのバイトコードをネイティブ コードにコンパイルして解釈します)。

実際、現在存在するすべての Ruby 実装はコンパイルされています。YARV と MRuby は独自の内部バイトコード形式にコンパイルされ、Rubinius、MacRuby、MagLev、および Topaz は独自の内部バイトコード形式にコンパイルされてから、それネイティブ コードにコンパイルされ、JRuby は JVM バイトコードにコンパイルされます ( JVM がさらにコンパイルする場合としない場合があります)、IronRuby は CIL バイトコードにコンパイルします (VES がさらにコンパイルする場合としない場合があります)。

Ruby がこのように振る舞うのは、言語仕様がそう言っているからです。Ruby が「解釈」されているからではなく、実際にはそうではないからです。Ruby の唯一の純粋に解釈された実装は、MRI と JRuby の非常に初期のバージョンであり、どちらも長い間廃止されています。

于 2015-02-27T15:11:14.383 に答える