Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Zuweisung nicht existierender Objekte

6 views
Skip to first unread message

Oliver Sch@d

unread,
Feb 28, 2012, 5:33:18 PM2/28/12
to
Heyho,

weil ich neulich in einem Vortrag darauf gestoßen bin und ich nicht darauf
komme, warum das so ist:

warum ergibt, wenn Objekt mit Namen "a" nicht definiert wurde, der
Ausdruck

a = a

ein nil?

a = b dagegen ergibt:
NameError: undefined local variable or method `b' for main:Object
from (irb):1
from :0

Ich hätte in beiden Fällen das gleiche Verhalten erwartet, da wie gesagt a
nicht vorher definiert wurde, genau wie b.

Tritt mit Ruby 1.8.7 und 1.9.2 so auf, ein Interpreter-Bug hätte da ja
schon absichtlich portiert werden müssen.

mfg
Oli

--
Man darf ruhig intelligent sein, man muss sich nur zu helfen wissen

Robert Klemme

unread,
Feb 29, 2012, 2:37:31 AM2/29/12
to
On 28.02.2012 23:33, Oliver Sch@d wrote:
> Heyho,
>
> weil ich neulich in einem Vortrag darauf gestoßen bin und ich nicht darauf
> komme, warum das so ist:
>
> warum ergibt, wenn Objekt mit Namen "a" nicht definiert wurde, der
> Ausdruck
>
> a = a
>
> ein nil?
>
> a = b dagegen ergibt:
> NameError: undefined local variable or method `b' for main:Object
> from (irb):1
> from :0
>
> Ich hätte in beiden Fällen das gleiche Verhalten erwartet, da wie gesagt a
> nicht vorher definiert wurde, genau wie b.
>
> Tritt mit Ruby 1.8.7 und 1.9.2 so auf, ein Interpreter-Bug hätte da ja
> schon absichtlich portiert werden müssen.

Ich denke, das ist ein Corner-Case: weil das Statement eine Zuweisung zu
a enthält, ist a ab diesem Statement definiert. Vermutlich hat man sich
die Mühe gespart, diesen Fall separat zu prüfen.

Ciao

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Simon Krahnke

unread,
Feb 29, 2012, 3:00:41 AM2/29/12
to
* Oliver Sch@d (23:33) schrieb:

> warum ergibt, wenn Objekt mit Namen "a" nicht definiert wurde, der
> Ausdruck
>
> a = a
>
> ein nil?

Weil Ruby in der Parse-Phase entscheidet, das a in diesem Kontext eine
lokale Variable ist. In der Ausführ-Phase findet dann die Zuweisung
statt. a ist definiert, also kein Problem.

mfg, simon .... l

Oliver Sch@d

unread,
Feb 29, 2012, 11:03:26 AM2/29/12
to
Robert Klemme wrote:

> Ich denke, das ist ein Corner-Case: weil das Statement eine Zuweisung zu
> a enthält, ist a ab diesem Statement definiert. Vermutlich hat man sich
> die Mühe gespart, diesen Fall separat zu prüfen.

Achso, du meinst, man erstellt erst das Objekt auf der linken Seite, weil
man ja zuweist, anschließend wird rechts auf der Seite der Ausdruck
ausgewertet. Mmh, könnte sein, klingt zumindest plausibel.

Robert Klemme

unread,
Feb 29, 2012, 11:59:22 AM2/29/12
to
Stimmt! Den "a" kann ja auch ein Methodenaufruf sein. Das stellt man
dann erst zur Laufzeit fest. Oliver, vergiss meine Erklärung: die hier
ist viel besser.

Oliver Sch@d

unread,
Feb 29, 2012, 1:22:42 PM2/29/12
to
Robert Klemme wrote:

> On 29.02.2012 09:00, Simon Krahnke wrote:
>> * Oliver Sch@d (23:33) schrieb:
>>
>>> warum ergibt, wenn Objekt mit Namen "a" nicht definiert wurde, der
>>> Ausdruck
>>>
>>> a = a
>>>
>>> ein nil?
>>
>> Weil Ruby in der Parse-Phase entscheidet, das a in diesem Kontext eine
>> lokale Variable ist. In der Ausführ-Phase findet dann die Zuweisung
>> statt. a ist definiert, also kein Problem.
>
> Stimmt! Den "a" kann ja auch ein Methodenaufruf sein. Das stellt man
> dann erst zur Laufzeit fest. Oliver, vergiss meine Erklärung: die hier
> ist viel besser.

Das mag ja sein, dass sie besser ist, aber ich verstehe sie nicht richtig.
Kann mir das jemand ausführlicher erklären?

Wenn ich das richtig verstehe, wird erstmal entschieden, dass a ein Objekt
sein muss und keine Methode, weil es auch links steht?

Und der Fehler resultiert bei a = b nur daher, dass man das bei b eben
nicht weiß, ob es Objekt oder Methode ist?

Robert Klemme

unread,
Feb 29, 2012, 4:38:21 PM2/29/12
to
On 29.02.2012 19:22, Oliver Sch@d wrote:
> Robert Klemme wrote:
>
>> On 29.02.2012 09:00, Simon Krahnke wrote:
>>> * Oliver Sch@d (23:33) schrieb:
>>>
>>>> warum ergibt, wenn Objekt mit Namen "a" nicht definiert wurde, der
>>>> Ausdruck
>>>>
>>>> a = a
>>>>
>>>> ein nil?
>>>
>>> Weil Ruby in der Parse-Phase entscheidet, das a in diesem Kontext eine
>>> lokale Variable ist. In der Ausführ-Phase findet dann die Zuweisung
>>> statt. a ist definiert, also kein Problem.
>>
>> Stimmt! Den "a" kann ja auch ein Methodenaufruf sein. Das stellt man
>> dann erst zur Laufzeit fest. Oliver, vergiss meine Erklärung: die hier
>> ist viel besser.
>
> Das mag ja sein, dass sie besser ist, aber ich verstehe sie nicht richtig.
> Kann mir das jemand ausführlicher erklären?
>
> Wenn ich das richtig verstehe, wird erstmal entschieden, dass a ein Objekt
> sein muss und keine Methode, weil es auch links steht?

Nein. "a" ist eine lokale _Variable_, kein Objekt. Variablen
beinhalten Referenzen auf Objekte. Dass es eine Variable ist, wird
festgelegt durch das Vorkommen von "a=". Das Auftreten von "a" ohne
folgendes Gleichheitszeichen kann entweder eine lokale Variable meinen
oder einen Methodenaufruf. Ab der Zeile, in der eine Variable definiert
wird, hat diese Priorität vor dem Methodenaufruf:

$ ruby19 -e '
> class X
> def a;99;end
> def b
> p a
> a = 1
> p a
> end
> end
> X.new.b
> '
99
1

Da bei der Zuweisung "a = a" die Variable definiert wird, wird das "a"
auf der rechten Seite als Variable betrachtet und kein Methodenaufruf
versucht. Der initiale Wert aller Variablen in Ruby is "nil".

> Und der Fehler resultiert bei a = b nur daher, dass man das bei b eben
> nicht weiß, ob es Objekt oder Methode ist?

Im Falle "a = b" wird "b" als Methode betrachtet, da es vorher kein "b="
gab. Allerdings wird erst zur Laufzeit erkannt, dass es die Methode
nicht gibt. Das muss so sein, da wegen Ruby's Dynamik die Methode immer
noch angelegt worden sein kann, bevor diese Code-Zeilen ausgeführt werden:

$ ruby19 -e '
> class X
> def m1
> a = b
> end
> end
> begin
> X.new.m1
> rescue Exception => e
> p e
> end
> class X
> def b;88;end
> end
> begin
> X.new.m1
> puts "ok"
> rescue Exception => e
> p e
> end
> '
#<NameError: undefined local variable or method `b' for #<X:0x2019cbdc>>
ok

Außerdem kann man das ja mit method_missing behandeln:

$ ruby19 -e '
> class X
> def m2
> a = b
> end
> def method_missing(*a,&b)
> printf "Ooops! %p\n", a
> end
> end
> X.new.m2
> '
Ooops! [:b]

Simon Krahnke

unread,
Mar 2, 2012, 2:38:33 AM3/2/12
to
* Robert Klemme <short...@googlemail.com> (2012-02-29) schrieb:

> Nein. "a" ist eine lokale _Variable_, kein Objekt. Variablen
> beinhalten Referenzen auf Objekte. Dass es eine Variable ist, wird
> festgelegt durch das Vorkommen von "a=". Das Auftreten von "a" ohne
> folgendes Gleichheitszeichen kann entweder eine lokale Variable meinen
> oder einen Methodenaufruf. Ab der Zeile, in der eine Variable definiert
> wird, hat diese Priorität vor dem Methodenaufruf:

Nun, auch ein Auftreten auf der linken Seite kann ein Methodenaufruf
sein. Ohne expliziten Empfänger ist es das aber anscheinend nie.

,----
| irb(main):001:0> def a= b; puts "a=#{b} called"; end
| => nil
| irb(main):002:0> a, self.a = 4,5
| a=5 called
| => [4, 5]
| irb(main):003:0> a
| => 4
|
| $ irb --version
| irb 0.9.5(05/04/13)
`----

mfg, simon .... l
Message has been deleted

Robert Klemme

unread,
Mar 2, 2012, 1:02:54 PM3/2/12
to
On 03/02/2012 12:27 PM, Oliver Sch@d wrote:
> Simon Krahnke wrote:
>
>> * Robert Klemme<short...@googlemail.com> (2012-02-29) schrieb:
>>
>>> Nein. "a" ist eine lokale _Variable_, kein Objekt. Variablen
>>> beinhalten Referenzen auf Objekte. Dass es eine Variable ist, wird
>>> festgelegt durch das Vorkommen von "a=". Das Auftreten von "a" ohne
>>> folgendes Gleichheitszeichen kann entweder eine lokale Variable
>>> meinen
>>> oder einen Methodenaufruf. Ab der Zeile, in der eine Variable
>>> definiert wird, hat diese Priorität vor dem Methodenaufruf:
>>
>> Nun, auch ein Auftreten auf der linken Seite kann ein Methodenaufruf
>> sein. Ohne expliziten Empfänger ist es das aber anscheinend nie.

Nicht nur anscheinend. "a=" ohne Empfänger ist _immer_ eine lokale
Variable - genau daran werden sie ja erkannt.

> Ohne die Diskussion beenden zu wollen: vielen Dank für eure Antworten,
> ihr habt mich weitergebildet.

Fein!

Ciao

robert

0 new messages