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...
endWhy? Because it’s shorter replacement for this:
class Foo
  attr_accessor :bar
  
  def initialize(bar)
    @bar = bar
  end
endThe other way to save typing on attributes lookes like this:
Foo = Struct.new(:bar) do
  # some methods...
endIt 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.