Struct is cleverer than the documentation claims

The Pickaxe book asserts that it will be possible to pass a block to
Struct.new in Ruby 1.9. While spelunking the code, I discovered that the
functionality has actually been present since 1.8.3. I've blogged about
this here:

But reading this mailing list, I notice that there's another way to
achieve a similar effect, specifically deriving from Struct.new.

So, both of the following achieve broadly the same effect:

Customer = Struct.new(:name, :address) do
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

class Customer < Struct.new(:name, :address)
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

Which leads to the question, what *are* the differences, and should I
prefer one approach over the other?

Thanks in advance for any light you can cast on this!

Paul.

···

--
Posted via http://www.ruby-forum.com/\.

Well, difference is that you get two classes vs. one class. I
frequently use the first idiom because I do not see the point in
creating two classes for this scenario. IMHO a base class makes sense
only if you want to inherit multiple times or separate concerns.
Neither is the case here.

Kind regards

robert

···

2007/9/4, Paul Butcher <paul@82ask.com>:

The Pickaxe book asserts that it will be possible to pass a block to
Struct.new in Ruby 1.9. While spelunking the code, I discovered that the
functionality has actually been present since 1.8.3. I've blogged about
this here:

钛刻专家——官网

But reading this mailing list, I notice that there's another way to
achieve a similar effect, specifically deriving from Struct.new.

So, both of the following achieve broadly the same effect:

> Customer = Struct.new(:name, :address) do
> def to_s
> "Customer called '#{name}' living at '#{address}'"
> end
> end

> class Customer < Struct.new(:name, :address)
> def to_s
> "Customer called '#{name}' living at '#{address}'"
> end
> end

Which leads to the question, what *are* the differences, and should I
prefer one approach over the other?

I too feel the block is better.

You can occasionally run into issues with the base class form. For example, when Rails does it's reloading magic on a file containing such a construct you will receive an error.

James Edward Gray II

···

On Sep 4, 2007, at 5:01 AM, Paul Butcher wrote:

So, both of the following achieve broadly the same effect:

Customer = Struct.new(:name, :address) do
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

class Customer < Struct.new(:name, :address)
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

Which leads to the question, what *are* the differences, and should I
prefer one approach over the other?

Thanks in advance for any light you can cast on this!

Why not reopen the class?

    Customer = Struct.new(:name, :address)
    class Customer
      def to_s
        "Customer called '#{name}' living at '#{address}'"
      end
    end

Paul

···

On Tue, Sep 04, 2007 at 07:01:15PM +0900, Paul Butcher wrote:

> Customer = Struct.new(:name, :address) do
> def to_s
> "Customer called '#{name}' living at '#{address}'"
> end
> end

> class Customer < Struct.new(:name, :address)
> def to_s
> "Customer called '#{name}' living at '#{address}'"
> end
> end

Why should I reopen a class if I can have everything with the block?

Customer = Struct.new :name, :address do
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

Kind regards

robert

···

2007/9/4, Paul Brannan <pbrannan@atdesk.com>:

On Tue, Sep 04, 2007 at 07:01:15PM +0900, Paul Butcher wrote:
> > Customer = Struct.new(:name, :address) do
> > def to_s
> > "Customer called '#{name}' living at '#{address}'"
> > end
> > end
>
> > class Customer < Struct.new(:name, :address)
> > def to_s
> > "Customer called '#{name}' living at '#{address}'"
> > end
> > end

Why not reopen the class?

    Customer = Struct.new(:name, :address)
    class Customer
      def to_s
        "Customer called '#{name}' living at '#{address}'"
      end
    end

I too feel the block is better.

You can occasionally run into issues with the base class form. For
example, when Rails does it's reloading magic on a file containing
such a construct you will receive an error.

I have some code in a Rails app which depends on a class derived from
Struct. I basically used that to create a presenter. I just switched
that class to a block form - I'd been using the class form - and the
unit tests all went nuts. Rails *thought* that its standard
expectation, that file xyz.rb will define Xyz, was violated. I got
"expected xyz.rb to define Xyz" errors, even though xyz.rb really
*did* define Xyz. So it kind of seems like a damned if you do, damned
if you don't here, with Structs and Rails.

···

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

Robert Klemme wrote:

Why should I reopen a class if I can have everything with the block?

Customer = Struct.new :name, :address do
  def to_s
    "Customer called '#{name}' living at '#{address}'"
  end
end

because, say, you'd want to add a constant to that class
   Customer = Struct.new :name, :address do
     K = 42
   end
   Customer::K
   (irb):7: warning: toplevel constant K referenced by Customer::K

Daniel

Robert Klemme wrote:
> Why should I reopen a class if I can have everything with the block?
>
> Customer = Struct.new :name, :address do
> def to_s
> "Customer called '#{name}' living at '#{address}'"
> end
> end

because, say, you'd want to add a constant to that class
   Customer = Struct.new :name, :address do
     K = 42
   end
   Customer::K
   (irb):7: warning: toplevel constant K referenced by Customer::K

This is workaroundable, if a bit ugly as I recently learned:
Customer = Struct.new :name, :address do
  self::K = 42
end
Customer::K

···

On 9/4/07, Daniel DeLorme <dan-ml@dan42.com> wrote:

Daniel