Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 913
Ben Avatar asked Dec 22 '11 11:12

Ben


People also ask

Why use Struct in Ruby?

A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class. The Struct class generates new subclasses that hold a set of members and their values. For each member a reader and writer method is created similar to Module#attr_accessor .

What is OpenStruct in Ruby?

An OpenStruct is a data structure, similar to a Hash , that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby's metaprogramming to define methods on the class itself.


4 Answers

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)
like image 125
Paolo Capriotti Avatar answered Nov 09 '22 17:11

Paolo Capriotti


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">
like image 23
sunkencity Avatar answered Nov 09 '22 15:11

sunkencity


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')
like image 29
tbuehlmann Avatar answered Nov 09 '22 16:11

tbuehlmann


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>
like image 26
Bohdan Avatar answered Nov 09 '22 17:11

Bohdan