8

я наткнулся на странное поведение рубина относительно определение переменной (и потерял коробку пончиков на пути):рубин определение переменной

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 

В скомпилированном языке это даже не компилируется.

  • Означает ли это, что рубин сохраняет ссылку на эту переменную, даже если она не прошла через этот фрагмент кода?
  • Если да, то насколько глубоко рассмотрены ifs/else для определения переменной?

Я действительно не могу поверить, что это ожидаемое поведение в рубине. И он не является специфичным для irb, его запуск в блоке кода ruby ​​/ rails дает тот же результат.

+3

Это потому, что Ruby устанавливает локальные области переменных во время разбора. 'a' используется как локальная переменная в этой области, поэтому Ruby рассматривает ее как локальную переменную (хотя она никогда не инициализируется). –

+0

@MarekLipka интересно. Я понял, что это может быть синтаксический анализ, поэтому я использовал тег AST для этого вопроса. – jlhonora

+4

Прочтите его из http://ruby-doc.org/core-2.1.2/doc/syntax/assignment_rdoc.html#label-Local+ Переменные + и + Методы –

ответ

3

В 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.)

В скомпилированном языке это даже не компилируется.

Нет такой вещи, как скомпилированный язык. Компиляция и интерпретация являются признаками компилятора или интерпретатора (duh!), А не языка. Языки не компилируются и не интерпретируются. Они всего лишь являются.

Каждый язык может быть реализован с помощью компилятора, и каждый язык может быть реализован с помощью интерпретатора. Большинство языков имеют как скомпилированные, так и интерпретированные реализации (например, C имеет GCC и Clang, которые являются компиляторами, а Cint и Cling - интерпретаторами, Haskell имеет GHC, который является компилятором, и Hugs, который является интерпретатором).

Многие современные языковые реализации имеют как в одной реализации, так и в разных фазах (например, YARV и MRuby компилируют исходный код Ruby на внутренний байт-код, а затем интерпретируют этот байт-код) или в смешанном режиме (например, HotSpot JVM оба интерпретируют и компилируют байт-код JVM, в зависимости от того, что имеет больше смысла) или оба (например, Rubinius компилирует исходный код Ruby в байт-код Rubinius на первом этапе, а затем компилирует этот байт-код на собственный код и интерпретирует его, в зависимости от того, что имеет больше смысла).

В самом деле, все существующие в настоящее время реализация на Ruby компилируются: YARV и MRuby компилировать свои собственные внутренние форматы байткодом, Rubinius, MacRuby, MagLev и Топаз компилировать свои собственные внутренние форматы байткодом, затем компилировать что к родным кода, JRuby компилируется в байт-код JVM (который JVM может или не может компилировать дополнительно), IronRuby компилируется в байт-код CIL (который VES может или не может компилировать далее).

Тот факт, что Ruby ведет себя таким образом, заключается в том, что спецификация языка так говорит. Не потому, что Ruby «интерпретируется», потому что на самом деле это не так. Единственной чисто интерпретируемой реализацией Ruby была МРТ и очень ранние версии JRuby, и они давно уже ушли на пенсию.

+0

Хороший призыв к аргументу компиляции, _программирование языков просто is_ - это фраза, которую я, вероятно, никогда не забуду – jlhonora

+0

Я не могу за нее похвастаться, я слышал это в интервью [Шрирам Кришнамурти] (http: //cs.brown.edu/~sk/), я считаю, что это был [этот] (http://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Web-Programming-with- Flapjax). –

1

Возможно, я ошибаюсь, но Ruby определяет области для ваших переменных. У вас есть глобальная область действия, которая составляет $

Тогда у вас есть локальная область действия вашего скрипта, который вы продемонстрировали в вопросе. Вы можете определить переменную внутри метода, но она по-прежнему будет доступна в локальной области исполняемого скрипта.

источник: http://ruby-doc.org//docs/ruby-doc-bundle/UsersGuide/rg/localvars.html

Вот это показано, что локальные переменные не имеют начальное значение ноль, но когда определено принимать любое значение они имеют, независимо от того, определяется.

2.1.5 :001 > p 1 
1 
=> 1 
2.1.5 :002 > p a 
NameError: undefined local variable or method `a' for main:Object 
    from (irb):2 
    from /Users/deh0002a/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>' 
2.1.5 :003 > if false 
2.1.5 :004?> a = 2 
2.1.5 :005?> else 
2.1.5 :006 >  a = 3 
2.1.5 :007?> end 
=> 3 
2.1.5 :008 > p a 
3 
=> 3 
2.1.5 :009 > p$a 
nil 
=> nil 
2.1.5 :010 > p @a 
nil 
=> nil 
2.1.5 :011 > 

Разница опять же связана с переменными Global и Instance. Даже когда они не определены, они автоматически принимают значение nil.

Смежные вопросы