Ben
Ben

Reputation: 1349

What's the purpose of an anonymous struct in Ruby?

They can be defined like this

Struct.new(:x, :y)

But what can usefully be done with them? Specifically, how can I create an instance of such a struct? This doesn't work

Struct.new(:x => 1, :y => 1)

(you get TypeError: can't convert Hash into String).

I'm using Ruby 1.9.2.

UPDATE:

Good pointers so far, thanks. I suppose the reason I asked this was that I have several times found myself wanting to do this

Struct.new(:x => 1, :y => 1)

just so that I can pass an object around where I can write obj.x instead of, say, instantiating a hash and having to write obj[:x]. In this case I want the structure to be really anonymous - I don't want to pollute my namespace with anything by naming what is returned from the Struct.new call. The closest thing to that, as already suggested is

Struct.new(:x, :y).new(1, 1)

But how do you like them apples? I'm not sure I do. Is it reasonable to expect to be able to define and instantiate an anonymous struct in one go (as part of core Ruby)? I guess when I read the official Ruby docs on Struct.new I assume the word 'anonymous' allows this, but it doesn't.

Upvotes: 7

Views: 5244

Answers (6)

Richard Jones
Richard Jones

Reputation: 4810

OpenStruct is probably what you want, but I ran into a situation recently where OpenStruct didn't work because I needed to raise an error when trying to access an undefined attribute. Struct does this:

os = OpenStruct.new
os.x = 1; os.y = 2;
os.z # returns nil

s = Struct.new(:x, :y).new
s.x = 1; s.y = 2;
s.z # raises NoMethodError

Just something to keep in mind.

Upvotes: 1

tbuehlmann
tbuehlmann

Reputation: 9110

Well, you can use Structs when you don't actually want to write a class with accessors. It's handy to just write

Project = Struct.new(:name)

instead of

class Project
  attr_accesor :name
end

As tokland pointed out correctly (thanks!), a Struct also gives you a nice #initialize method automagically. So the following is possible without any further code:

Project = Struct.new(:name)
p = Project.new('Quadriloptic Curves')

Upvotes: 4

Paolo Capriotti
Paolo Capriotti

Reputation: 4072

Struct.new returns a Class, so you can, for example, assign it to a constant like this:

Point = Struct.new(:x, :y)

or subclass it:

class Point < Struct.new(:x, :y)
  # custom methods here
  # ...
end

In both cases, you can use the resulting class like this:

Point.new(3, 5)

If you don't want to create a specific class (because you need to instantiate an object of that class only once), consider to use OpenStruct instead:

require 'ostruct'

point = OpenStruct.new(:x => 3, :y => 5)

Upvotes: 19

gilligan
gilligan

Reputation: 508

As for creating instances:

User = Struct.new(:user,:password)
u = User.new("john","secret")

Upvotes: 0

sunkencity
sunkencity

Reputation: 3472

You first create a struct, and then you can create instances of it. It's a way of creating data objects without having to declare a class. Basically it's the same as a hash, but it's more clean to access the objects. You can get stuff out of it by referencing it via ordinary accessor methods.

http://www.ruby-doc.org/core-1.9.3/Struct.html

# Create a structure with a name in Struct
Struct.new("Customer", :name, :address)    #=> Struct::Customer
Struct::Customer.new("Dave", "123 Main")   #=> #<struct Struct::Customer name="Dave", address="123 Main">

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

Upvotes: 5

Bohdan
Bohdan

Reputation: 8408

I'm hot sure about purpose but Struct.new returns class so

irb(main):001:0> Struct.new(:x,:y)
=> #<Class:0x2914110>
irb(main):002:0> Struct.new(:x,:y).new(1,2)
=> #<struct x=1, y=2>

Upvotes: 3

Related Questions