I’ve recently spotted a curious trend in blogposts about Ruby. It’s the way people define classes in examples. It goes like this:
class Foo < Struct.new(:bar)
# some methods...
end
Why? Because it’s shorter replacement for this:
class Foo
attr_accessor :bar
def initialize(bar)
@bar = bar
end
end
The other way to save typing on attributes lookes like this:
Foo = Struct.new(:bar) do
# some methods...
end
It brought up an interesting discussion on twitter, when @jeg2 said he didn’t like the practice. One important consequence of using it that was mentioned in this discussion is changing of ancestor chain.
When declaring class usual way:
Foo.ancestors
=> [Foo, Object, Kernel, BasicObject]
When inheriting from Struct.new
:
Foo.ancestors
=> [Foo, #<Class:0x00000001d41100>, Struct, Enumerable, Object, Kernel, BasicObject]
When creating a constant from Struct.new
:
Foo.ancestors
=> [Foo, Struct, Enumerable, Object, Kernel, BasicObject]
Have you noticed Enumerable
in two later cases? It means that suddenly instances of your class start to respond to each
method and a bunch of other methods. So it’s better be careful using Struct
like this.