Drew Dara-Abrams
Drew Dara-Abrams

Reputation: 8054

subclassing from a Struct vs. using attr_accessible

In Ruby 1.8.6, I could write class PerformableMethod < Struct.new(:object, :method, :args)

Now in Ruby 1.9.3, that throws an error: superclass mismatch for class PerformableMethod

It works if I change the code to:

class PerformableMethod
    attr_accessor :object, :method_name, :args

But why doesn't the struct work?

Upvotes: 1

Views: 424

Answers (2)

clacke
clacke

Reputation: 8066

The class name is optional also in 1.9 and 2.0. The problem is this:

> Struct.new(:asdf, :qwer) == Struct.new(:asdf, :qwer)
 => false 

Even if you provide a class name for your Struct:

> Struct.new("Zxcv", :asdf, :qwer) == Struct.new("Zxcv", :asdf, :qwer)
(irb):22: warning: redefining constant Struct::Zxcv
 => false 

This means that if you have this in a file that you load or require:

class MyClass < Struct.new(:qwer, :asdf)
  def some_method
    puts "blah"
  end
end

... then if you load it again -- maybe because you changed something and you want to try it without restarting irb, or maybe you are running Rails in dev mode and it reloads classes on each request -- then you get the exception:

TypeError: superclass mismatch for class MyClass

... because every time your class definition runs, it is declaring a brand new Struct as the superclass of MyClass. Providing a class name to Struct.new() does not help, as seen in the second code block; That just adds a warning about redefining a constant, and then opening the class fails anyway.

The only way to avoid the exception is to stash your Struct in a constant somewhere you control and make sure not to change that constant when the file is reloaded.

Upvotes: 5

Drew Dara-Abrams
Drew Dara-Abrams

Reputation: 8054

While typing out this question, my colleague sitting right next to me figured it out.

Struct now takes the class name as its first parameter.

So in Ruby 1.9.3 the following works:

class << Struct.new('PerformableMethod', :object, :method, :args)

Upvotes: 0

Related Questions