RE: [ruby-de] Re: [ruby-de] Re: [ruby-d e] Re: [ruby-d e] Problem Klassenvariable über schreiben
"Christoph" <[email protected]>
| Newsgroups | gmane.comp.lang.ruby.german |
|---|---|
| Message-ID | <000101c21a05$58f58800$0100a8c0@lony> |
> Pit Capitain
...
> Dass das ursprüngliche Beispiel bei 1.6.6 überhaupt mit Tricks zum
> Laufen gebracht werden kann, bei 1.6.7 aber nicht mehr, muss man nicht
> als "weniger" (Funktionalität) interpretieren. Die beispielsweise von
> Java bekannten Klassen-Variablen entsprechen bei Ruby den
> Klassen-Instanz-Variablen (mit einem @). Die gewünschte Funktionalität
> ist also da, es gibt nur ein Problem mit der Benennung.
>
> Etwas wie die Klassen-Variablen von Ruby (mit @@) gibt es in Java
> nicht: Variablen, die nicht nur zu einer Klasse, sondern zu einer
> ganzen Klassenhierarchie gehören. Deren Verhalten ist bei 1.6.7
> korrigiert worden. Nun spielt es anscheinend keine Rolle mehr, in
> welcher Reihenfolge die Klassen-Variablen definiert werden, so wie es
> noch bei 1.6.6 der Fall war.
Das ist so nicht richtig. Die Reihenfolge ist immer noch
sehr wichtig das Beispiel bringt dies allerdings nicht
heraus. (In 1.7 bekommst du eine Warnung wenn du auf der
``unsinnige Reihenfolge insistierst.) Klassen-Variablen
sind eigentlich globale Variablen die allerdings nicht in
allen ``Namens-Räumen sichtbar sind, wobei ein ``Namen-Raum
eine Klasse oder Module sein kann. (Ich verwende den Terminus
Klassen-Variable synonym für die artverwandte Modul-Variable).
Die Sichtbarkeits-Regel für Rubys Klassen-Variablen und
Konstanten sind offenbar Smalltalk entlehnt (static or global
scope) und haben mit den Sichtbarkeits-Regeln von C++ oder Java
(local or relative scope) wenig gemein.
Der Eindruck, dass die Sichtbarkeit von Klassen-Konstanten
und Variablen scheinbar doch ``locale-scope Regeln folgt,
ist ein gewollter Artfakt von Rubys Kode-Konventionen. Wenn
man diese Konventionen bewusst verletzt kann zum Bespiel eine
äussere Klasse als Kind seiner inneren Klasse konstruieren.
---
# Die Beispiele benötigen zum Teil Version 1.7.
inner = Class.new
Outer = Class.new(inner)
Outer.const_set :Inner, inner
p Outer.superclass # => Outer::Inner
# funktioniert wirklich!
class Outer
class Inner
def foo
"Outer::Inner rules"
end
end
end
p Outer.new.foo # => "Outer::Inner rules"
class A
# erzeuge `@@a'
@@a = 'a'
# `@@a' ist jetzt sichtbar im Namens-Raum A
def see_a
# verwende A::@@a
@@a
end
end
p A.new.see_a # => 'a'
class B < A
# im Namens-Raum B sind alle Klassen-variablen des
# Namens-Raum A sichtbar. Die Zeile
@@a = 'b'
# definiert somit keine neue Klassen-variable `B::@@a',
# sondern der Wert der bereits vorhandenen
# Klassen-Variable A::@@a ist nun 'b'.
def see_a_in_b
# verwendet A::@@a
@@a
end
end
p A.new.see_a # => 'b'
p B.new.see_a # => 'b'
p B.new.see_a_in_b # => 'b'
class B
# neue Klassen-Variable B::@@b
@@b = 'b'
def see_b_in_B
# verwendet B::@@b
@@b
end
end
class A
# erzeuge neue Klassen-Variable A::@@b
@@b = 'a'
# Der Umstand dass in As Unterklasse B eine
# Klassen-Variable Namens @@b definiert wurde
# ist völlig unerheblich.
def see_b
# dies verwendet A::@@a dies gilt damit auch
# für Instanzen der Unterklassen von A
@@b
end
end
p A.new.see_b # => 'a'
p B.new.see_b # => 'a'
p B.new.see_b_in_B # => 'b'
# Klassen-Variablen als globale Variablen
@@top = 'etwas'
# ist äquivalent zu
# class Object
# @@top = 'etwas'
# end
class A
# A erbt Objects Klassen-Variablen,
# deshalb ist Object::@@top sichtbar
p @@top # => etwas
end
# extra Verwirrung
class X
@@y = '@@y in X'
end
class Y
@@x = '@@x in Y'
end
class X
# Definiere eine Y Singleton-Methode.
def Y.see_y_in_X
# benutzte X::@@y
@@y
end
end
class Y
# Definiere eine X Singleton-Methode.
def X.see_x_in_Y
# benutzte Y::@@y
@@x
end
end
p Y.see_y_in_X # => '@@y in X'
p X.see_x_in_Y # => '@@x in Y'
# Modul-variablen
module M
@@rule = 'M rules'
def m
@@rule
end
end
class G
@@rule = 'G rules'
include M
end
class H < G
def h
@@rule
end
end
p H.new.h # => 'G rules'
p H.new.m # => 'M rules'
# das geht nur in ruby-1.7
=begin
class E
@@e = 'ich sehe Es Klassen-Variablen'
$body = proc {|| @@e }
end
class F
@@e = "diese Klassen-Variable wird ignoriert"
define_method(:see_e, $body)
end
p F.new.see_e # => ich sehe Es Klassen-Variablen
=end
---
---
# Eine Implementation von Klassen-Attributen
# basiert auf Klassen-instanz-variablen
class A
@me = 'you'
def me
type.me
end
def me=(rhs)
type.me = rhs
end
class << self
attr_accessor :me
end
end
class B < A; end
B.me = 'her'
p A.new.me # => 'you'
p B.new.me # => 'her'
p B.me # => 'her'
# Autmatisierte Version
class Class
def class_attr_accessor (sym, instance_visibility = protected,
class_visibility = private )
class_eval <<-attr_body
#{instance_visibility}
def #{sym.to_s}; type.#{sym.to_s} end
def #{sym.to_s}=(rhs); type.#{sym.to_s}=(rhs) end
attr_body
class << self; self end.send(:attr_reader,sym,class_visibility)
class << self; self end.send(:attr_writer,sym,class_visibility)
end
end
class A
class_attr_accessor :you,:public,:public
end
p A.you = 'me'
p B.you = 'him'
p A.new.you # => 'me'
p B.new.you # => 'him'
p B.you # => 'him'
---
/Christoph