class A
HELLO = “Hello I’m A”
def hello
puts HELLO
end
end
class B < A
HELLO = “Hello I’m B”
def hello2
puts HELLO
end
end
B.new.hello
=> “Hello I’m A” (ouch…)
B.new.hello2
=> “Hello I’m B”
Workaround (but ugly):
class A
def hello
puts self.class::HELLO
end
end
So, if a contstant appears within a method, its value is evaluated for
the class in which such method is defined (“hello” is defined in class
A not in B, so it takes HELLO from class A).
I don’t like this behavior (just my opinion). Do I miss something?
Regards.
On Aug 14, 2011, at 9:31 AM, Iaki Baz C. wrote:
HELLO = “Hello I’m B”
B.new.hello2
=> “Hello I’m B”
Correct, since the method is being called in the context of A, it will
search starting from A. You can verify this by printing out the
Module.nesting value which is used for constant lookup searching:
class A
HELLO = “Hello I’m A”
def hello
p Module.nesting
puts HELLO
end
end
This will output [A].
So, if a contstant appears within a method, its value is evaluated for
the class in which such method is defined (“hello” is defined in class
A not in B, so it takes HELLO from class A).
I don’t like this behavior (just my opinion). Do I miss something?
This behavior can fortunately be overridden by simply overriding the
hello method in the B class, meaning that it will use the constant
defined in B instead:
class A
HELLO = “Hello I’m A”
def hello
puts HELLO
end
end
class B < A
HELLO = “Hello I’m B”
def hello
puts HELLO
end
def hello2
puts HELLO
end
end
B.new.hello
2011/8/14 Chris W. [email protected]:
This behavior can fortunately be overridden by simply overriding the hello
method in the B class, meaning that it will use the constant defined in B instead
Yes, but it requires duplicating code. In my case I’ve a server class:
class Server
def self.foo
puts “I listen in IP #{IP}”
end
end
and then some classes inhereting from it:
class UdpServer < Server
IP = “1.2.3.4”
end
class TcpServer < Server
IP = “1.2.3.5”
end
Of course “TcpServer.foo” fails:
NameError: uninitialized constant Server::IP
So I must use workarounds like:
class Server
def self.foo
puts “I listen in IP #{self::IP}”
end
end
class UdpServer < Server
IP = “1.2.3.4”
end
class TcpServer < Server
IP = “1.2.3.5”
end
Then it works:
TcpServer.foo
=> I listen in IP 1.2.3.5
UdpServer.foo
=> I listen in IP 1.2.3.4
On Sun, Aug 14, 2011 at 8:40 PM, Iaki Baz C. [email protected]
wrote:
Yes, but it requires duplicating code. In my case I’ve a server class:
What about Modules?
Create a Server module with Server logic, and mix that into your
classes.
–
Phillip G.
phgaw.posterous.com | twitter.com/phgaw | gplus.to/phgaw
A method of solution is perfect if we can forsee from the start,
and even prove, that following that method we shall attain our aim.
– Leibniz
2011/8/14 Phillip G. [email protected]:
What about Modules?
Create a Server module with Server logic, and mix that into your classes.
It’s the very same:
module M
def foo
puts “HELLO = #{HELLO}”
end
end
class A
HELLO = “I’m A”
extend M
end
A.foo
=> NameError: uninitialized constant M::HELLO
Does Ruby violate the DRY principle here?
On Aug 14, 2011, at 11:40 AM, Iaki Baz C. wrote:
end
IP = “1.2.3.5”
end
Of course “TcpServer.foo” fails:
NameError: uninitialized constant Server::IP
I suppose the question then becomes why they have to be constants at
that level. By using a module and doing a mixin (as I notice that Philip
just mentioned as I’m writing this):
module Server
def listen(ip)
# Would most likely set instance variable @ip for later use
@ip = ip
puts “Listening on #@ip”
end
end
class UdpServer
include Server
def listen(ip)
puts “UDP Listen”
super
end
end
class TcpServer
include Server
end
TcpServer.new.listen(“1.2.3.4”)
UdpServer.new.listen(“1.2.3.5”)
The listen logic is centralized, and as shown in the UdpServer class,
you can override the Server listen and still call its core functionality
through super
. This works out because including modules inserts into
the object hierarchy as shown by doing a p TcpServer.ancestors:
[TcpServer, Server, Object, Kernel, BasicObject]
Regards,
Chris W.
http://www.twitter.com/cwgem
On Aug 14, 2011, at 12:19 PM, Iaki Baz C. wrote:
2011/8/14 Chris W. [email protected]:
The listen logic is centralized, and as shown in the UdpServer class, you can
override the Server listen and still call its core functionality through super
Hi. My code uses classes rather than instance of classes. Each class
(i.e. UdpServer, TcpServer) has different attributes (listenting IP,
port, transport, and so) and I don’t want (due to efficience) to
assign the same value in initialize method for every instance.
If they need to stay as classes and not instances, then I recommend the
use of a class instance variable:
class Server
def self.listen
puts “Listening on #@ip”
end
end
class UdpServer < Server
@ip = “1.2.3.4”
end
class TcpServer < Server
@ip = “5.6.7.8”
end
UdpServer.listen
TcpServer.listen
2011/8/14 Chris W. [email protected]:
The listen logic is centralized, and as shown in the UdpServer class, you can
override the Server listen and still call its core functionality through super
Hi. My code uses classes rather than instance of classes. Each class
(i.e. UdpServer, TcpServer) has different attributes (listenting IP,
port, transport, and so) and I don’t want (due to efficience) to
assign the same value in initialize method for every instance.
2011/8/14 Chris W. [email protected]:
class TcpServer < Server
@ip = “5.6.7.8”
end
UdpServer.listen
TcpServer.listen
Yes, I also us that commonly. However I didn’t know that class
instance variables can be defined out of a method. I expected:
class TcpServer < Server
def self.init_variables
@ip=“5.6.7.8”
end
end
Good to know that it’s not needed 
On Aug 14, 2011, at 10:31 AM, Iaki Baz C. wrote:
So, if a contstant appears within a method, its value is evaluated for
the class in which such method is defined (“hello” is defined in class
A not in B, so it takes HELLO from class A).
I don’t like this behavior (just my opinion). Do I miss something?
class A
class << self
attr_accessor :hello
end
@hello = “Hello I’m A”
def hello
puts self.class.hello
end
end
class B < A
@hello = “Hello I’m B”
def hello2
puts self.class.hello
end
end
B.new.hello
#=> “Hello I’m B”
B.new.hello2
#=> “Hello I’m B”
Yes, I also us that commonly. However I didn’t know that class
instance variables can be defined out of a method. I expected:
class TcpServer < Server
def self.init_variables
@ip=“5.6.7.8”
end
end
Good to know that it’s not needed 
Yup, and the reason why it works is because class definitions are
expressions, where the last expression in the class body is the return
of the expression. Since in most cases it’s a method definition, the
result is generally nil. So what happens is:
class TcpServer < Server
def self.init_variables
Notice we have to use self here so it works when calling
TcpServer.init_variables. This is because we’re at the class declaration
stage, so self is set to TcpServer. This binds the method to the
specific TcpServer class instead of the instances of the class. So @ip
outside of a method declaration is the same principal, as when instance
variables are created and accessed, they’re bound to the value of self
(You can see this at the bytecode / c level here if you want
http://blog.rubychest.net/2011/08/know-they-self-instance-variables.html
).
Regards,
Chris W.
http://www.twitter.com/cwgem
I may be late to the party, since it seems like you’ve already solved
the problem, but Ruby has a const_missing method, which works just
like method_missing. You could use it to search for constants in
various places.
http://www.ruby-doc.org/core/classes/Module.html#M000489
– Matma R.
2011/8/14 Bartosz Dziewoński [email protected]:
I may be late to the party, since it seems like you’ve already solved
the problem, but Ruby has a const_missing method, which works just
like method_missing. You could use it to search for constants in
various places.
Thanks, but I don’t think that mechanism is as efficient as using
class instance variables (this is, @attributes belonging to the class
itself).
Thanks a lot.
2011/8/15 Brian C. [email protected]:
Change
puts HELLO
to
puts self.class::HELLO
and it should work the way you want.
Ruby’s constant resolution is static, unless you force it to be dynamic
Yes, I’ve also used this mechanism (self.class::HELLO). And also using
class instance variables.
“Iñaki Baz C.” [email protected] wrote in post #1016621:
class A
HELLO = “Hello I’m A”
def hello
puts HELLO
end
end
class B < A
HELLO = “Hello I’m B”
def hello2
puts HELLO
end
end
Change
puts HELLO
to
puts self.class::HELLO
and it should work the way you want.
Ruby’s constant resolution is static, unless you force it to be dynamic
this way.