tags:

views:

488

answers:

3

A Ruby Struct allows an instance to be generated with a set of accessors:

# Create a structure named by its constant
Customer = Struct.new(:name, :address)     #=> Customer
Customer.new("Dave", "123 Main")           #=> #<Customer name="Dave", address="123 Main">

This looks convenient and powerful, however, a Hash does something pretty similar:

Customer = {:name => "Dave", :address => "123 Main"}

What are the real-world situations where I should prefer a Struct (and why), and what are the caveats or pitfalls in choosing one over the other?

A: 

Why not specify a customer class in such a scenario? Convenience?

Andrew Grimm
Using Customer = Struct.new does define a Customer class, just with certain default behaviour. You can easily modify or override this behaviour if you wish.
tomafro
+6  A: 

Personally I use a struct in cases when I want to make a piece of data act like a collection of data instead of loosely coupled under a Hash.

For instance I've made a script that downloads videos from Youtube and in there I've a struct to represent a Video and to test whether all data is in place:


Video = Struct.new(:title, :video_id, :id) do
  def to_s
    "http://youtube.com/get_video.php?t=#{id}&video_id=#{video_id}&fmt=18"
  end

  def empty?
    @title.nil? and @video_id.nil? and @id.nil?
  end
end

Later on in my code I've a loop that goes through all rows in the videos source HTML-page until empty? doesn't return true.

Another example I've seen is James Edward Gray IIs configuration class which uses OpenStruct to easily add configuration variables loaded from an external file:

#!/usr/bin/env ruby -wKU

require "ostruct"

module Config
  module_function

  def load_config_file(path)
    eval <<-END_CONFIG
    config = OpenStruct.new
    #{File.read(path)}
    config
    END_CONFIG
  end
end

# configuration_file.rb
config.db = File.join(ENV['HOME'], '.cool-program.db')
config.user = ENV['USER']

# Usage:
Config = Config.load_config('configuration_file.rb')
Config.db   # => /home/ba/.cool-program.db
Config.user # => ba
Config.non_existant # => Nil

The difference between Struct and OpenStruct is that Struct only responds to the attributes that you've set, OpenStruct responds to any attribute set - but those with no value set will return Nil

ba
Why doesn't all the code I wrote get shown here but if I go to edit the post I see it all and it looks great in the preview?
ba
The << screwed it up, turned it into << and now all is great. :)
ba
Thanks, these are good examples. The first one seems to clearly demonstrate the advantages of Struct. The second one, while a nice example, would work just as well as a Hash wouldn't it?
Walt Gordon Jones
Yeah the second example could also just be a Hash, personally I just like the syntax better for a configuration file like that. Plus when writing programs where programmers aren't the ones configuring I think `config.value = 'something'` is a bit clearer than: `config[:value] => 'something'`. A matter of taste :)
ba
+1  A: 

A Struct has the feature that you can get at its elements by index as well as by name:

irb(main):004:0> Person = Struct.new(:name, :age)
=> Person
irb(main):005:0> p = Person.new("fred", 26)
=> #
irb(main):006:0> p[0]
=> "fred"
irb(main):007:0> p[1]
=> 26
irb(main):008:0> p.name
=> "fred"
irb(main):009:0> p.age
=> 26

which sometimes is useful.

JDonner