# An alternative to the class Foo \< Struct.new(vars) idiom and

**URL:** <https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202>\
**Category:** Ruby\
**Created:** [June 1, 2006, 1:55pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202 "2006-06-01T13:55:30Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 1:55pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/1 "2006-06-01T13:55:30Z")

</div>

I wrote this a couple weeks ago  
( [eigenclass.org](http://eigenclass.org/hiki.rb?struct-alike+class+definition) ) and was  
considering whether it deserves an actual release. The implementation is  
simple; taking just 40 lines of code, it allows you to do stuff like

class MyClass \< SuperClass.new(:a, :b) # doubly appropriate 🙂  
def sum  
@a + @b  
end  
end  
a = MyClass.new(1, 1)  
a # =\> #\<MyClass:0xb7dfd254 @b=1,  
@a=1\>  
a.sum # =\> 2

The generated class uses normal instance variables unlike Struct.new,  
and  
creates the accessors for you.

You also get keyword arguments for free:

b = MyClass.new :a =\> 1, :b =\> 41  
b.sum # =\> 42  
b # =\> #\<MyClass:0xb7dfd024 @b=41,  
@a=1\>  
b.b # =\> 41

Default values are handled as follows:

class Foo \< SuperClass.new(:text, :times) { @times ||= 2 }  
def greeting  
([“Hello, #{@text}”] \* times).join(“\n”)  
end  
end

Foo.new(“SuperClass”, 2).greeting # =\> “Hello, SuperClass\nHello,  
SuperClass”  
Foo.new(:text =\> “world”).greeting # =\> “Hello, world\nHello, world”

Unlike Struct.new, you can use SuperClass to generate classes in the  
middle  
of the inheritance chain:

class X  
attr\_reader :foo  
def initialize(foo = 1)  
@foo = foo  
end  
end

class Y \< SuperClass.new(:bar, :baz, X) {@baz ||= 10;  
initialize\_super(@baz + 1) }  
def fubar; @foo + @baz end  
end

Y.new(10, 1).foo # =\> 2  
Y.new(:bar =\> 1).fubar # =\> 21

I have an extended implementation that also creates #eql?, #hash and #==  
methods with selectable semantics.

Here’s the basic implementation:

# Copyright (C) 2006 Mauricio F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

[http://eigenclass.org](http://eigenclass.org)

# Use and distribution under the same terms as Ruby.

class SuperClass  
def self.new\_class(accessor\_type, \*args, &block)  
parent = args.pop if Class === args.last  
parent ||= Object  
unless args.size \> 1  
raise ArgumentError, “No point in using SuperClass for a single  
argument!”  
end  
Class.new(parent) do  
@initialize\_args = args.map{|x| “@#{x}”.intern}  
class \<\< self; attr\_reader :initialize\_args end  
case accessor\_type  
when :ro : attr\_reader(\*args)  
when :rw : attr\_accessor(\*args)  
end

```
  define_method(:initialize) do |*a|
    args.each{|name| instance_variable_set("@#{name}", nil) }
    if a.size == 1 && Hash === a[0]
      args.each{|name| instance_variable_set("@#{name}", 

```

a[0][name.to\_sym])}  
elsif a.size != args.size  
raise ArgumentError,  
“wrong number of arguments (#{a.size} for #{args.size})”  
else  
args.each\_with\_index{|name, i|  
instance\_variable\_set(“@#{name}”, a[i])}  
end  
instance\_eval(&block) if block  
end

```
  if block
    super_meth = parent.instance_method(:initialize)
    define_method(:initialize_super){|*a| 

```

super\_meth.bind(self).call(\*a) }  
private :initialize\_super  
end  
end  
end

def self.new(\*args, &block); new\_class(:ro, \*args, &block) end  
def self.new\_rw(\*args, &block); new\_class(:rw, \*args, &block) end  
end

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 2:34pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/2 "2006-06-01T14:34:59Z")

</div>

Mauricio F. wrote:

> a = MyClass.new(1, 1)  
> b # =\> #\<MyClass:0xb7dfd024 @b=41, @a=1\>  
> Foo.new(“SuperClass”, 2).greeting # =\> “Hello, SuperClass\nHello, SuperClass”  
> @foo = foo
> 
> ```
> parent = args.pop if Class === args.last
> end
> end
> 
> ```
> 
> def self.new(\*args, &block); new\_class(:ro, \*args, &block) end  
> def self.new\_rw(\*args, &block); new\_class(:rw, \*args, &block) end  
> end

I’m sold. This will be great for easily defining event types in  
EventMachine. Why the complicated default argument values though? For  
simple cases how about just using hash syntax:

MyClass = SuperClass.new(:a =\> 2, :b =\> 3)

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 3:59pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/3 "2006-06-01T15:59:48Z")

</div>

On Thu, Jun 01, 2006 at 09:33:29PM +0900, Jeff R. wrote:

> I’m sold. This will be great for easily defining event types in  
> EventMachine. Why the complicated default argument values though? For  
> simple cases how about just using hash syntax:
> 
> MyClass = SuperClass.new(:a =\> 2, :b =\> 3)

The problem with this is that it makes positional arguments impossible,  
since  
the Hash doesn’t preserve the order; maybe

```
MyClass = SuperClass.new(:a, 2, :b, 3)

```

or  
MyClass = SuperClass.new(:a, :b, :a =\> 2, :b =\> 3)  
# (don’t like the repetition though)  
?

Anyway, I realized I can remove a couple lines from SuperClass to turn  
the  
following (which I forgot to show in the previous msg) into the  
preferred  
style:

# b is optional only when using the keyword arg style

class Foo \< SuperClass.new(:a, :b)  
def initialize(\*args)  
super  
@b ||= “foo”  
end  
end

which will look better than passing a block to SuperClass.new for most  
people.

Maybe I should allow both styles:

- mandatory keyword arguments, with default values specified in the  
SuperClass.new call (have to define how, two possibilities given above  
but  
there’s probably a better way)
- either full positional arguments or keyword arguments (at least one  
required  
to discriminate), default values set manually in #initialize as in the  
above  
example.

The desired one could be specified either via an explicit call  
(SuperClass.new\_kw\_args vs. SuperClass.new\_positional ?) or implicitly  
by the  
arguments given to SuperClass.new.

It’s all easy to implement but there are many options…

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 5:29pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/4 "2006-06-01T17:29:33Z")

</div>

On Thu, 1 Jun 2006, Mauricio F. wrote:

hi mauricio-

thought i’d just chime in here and show how this would be done with  
traits  
since it has overlapping aims:

> creates the accessors for you.
> 
> You also get keyword arguments for free:
> 
> b = MyClass.new :a =\> 1, :b =\> 41  
> b.sum # =\> 42  
> b # =\> #\<MyClass:0xb7dfd024 @b=41, @a=1\>  
> b.b # =\> 41

```
 harp:~ > cat a.rb
 require 'traits'
 class MyClass
   include TraitInit
   trait_initialize 'a', 'b'
   def sum() a + b end
 end

 a = MyClass.new 40, 2
 p a.a
 p a.b
 p a.sum

 a = MyClass.new 'b' => 2, 'a' => 40
 p a.a
 p a.b
 p a.sum

 p MyClass.traits

 harp:~ > ruby a.rb
 40
 2
 42
 40
 2
 42
 [["a", "a="], ["b", "b="]]

```

> Default values are handled as follows:
> 
> class Foo \< SuperClass.new(:text, :times) { @times ||= 2 }  
> def greeting  
> ([“Hello, #{@text}”] \* times).join(“\n”)  
> end  
> end
> 
> Foo.new(“SuperClass”, 2).greeting # =\> “Hello, SuperClass\nHello, SuperClass”  
> Foo.new(:text =\> “world”).greeting # =\> “Hello, world\nHello, world”

```
 harp:~ > cat a.rb
 require 'traits'

 class MyClass
   include TraitInit
   trait_initialize 'a' => 40, 'b' => 2
   def sum() a + b end
 end

 class MyClass2 < MyClass; end

 p MyClass.new.sum

 p MyClass2.new.sum

 harp:~ > ruby a.rb
 42
 42

```

note that it works with inheritence too.

> class Y \< SuperClass.new(:bar, :baz, X) {@baz ||= 10; initialize\_super(@baz + 1) }  
> def fubar; @foo + @baz end  
> end
> 
> Y.new(10, 1).foo # =\> 2  
> Y.new(:bar =\> 1).fubar # =\> 21

```
 harp:~ > cat a.rb
 require 'traits'

 class X
   include TraitInit
   trait_initialize
   trait :foo => 1
 end

 class Y < X
   trait :bar, :baz => 10
   trait(:foo){ baz + 1 }
   def fubar() foo + baz end
 end

 p Y.new(:bar => 10, :baz => 1).foo
 p Y.new(:bar => 1).fubar

 harp:~ > ruby a.rb
 2
 21

```

traits is here if anyone is interested

[http://rubyforge.org/projects/codeforpeople/](http://rubyforge.org/projects/codeforpeople/)  
[http://codeforpeople.com/lib/ruby/traits](http://codeforpeople.com/lib/ruby/traits)

kind regards.

-a

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 7:22pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/5 "2006-06-01T19:22:30Z")

</div>

On Fri, Jun 02, 2006 at 12:27:32AM +0900, removed\_email\_address@domain.invalid wrote:

> On Thu, 1 Jun 2006, Mauricio F. wrote:
> 
> thought i’d just chime in here and show how this would be done with traits  
> since it has overlapping aims:

[…]

Please indulge some quick questioning on my part; all the answers are in  
the  
sources but my eyeballs hurt a bit atm. and I’d prefer to avoid reading  
traits-0.9.1.rb’s ~700 lines of code 🙂 After a cursory look, it’s  
clear  
traits and SuperClass are in different leagues. SuperClass goes for  
minimalism  
and meta-programming self-restraint (no methods added to core classes,  
no  
hooks used…); traits seems to do so much more and pays the cost (I can  
see a  
load of methods/instance variables being added at Object’s level,  
Object.singleton\_method\_added, etc.).

> ```
> harp:~ > cat a.rb
> require 'traits'
> class MyClass
> include TraitInit
> trait_initialize 'a', 'b'
> def sum() a + b end
> end
> 
> ```

Would def sum; @a + @b end also work?  
Plain instance variables are the main appeal of SuperStruct or  
SuperClass.

> > Unlike Struct.new, you can use SuperClass to generate classes in the middle  
> > of the inheritance chain:

[…]

> ```
> trait :bar, :baz => 10
> trait(:foo){ baz + 1 }
> def fubar() foo + baz end
> end
> 
> p Y.new(:bar => 10, :baz => 1).foo
> p Y.new(:bar => 1).fubar
> 
> ```

Interesting. Can this be made to work if X is defined as  
class X  
attr\_reader :foo  
def initialize(foo); @foo = foo end  
end  
and doesn’t include TraitInit, or when it does something non-trivial in  
#initialize? In other words, is it possible to have a single class in  
the  
hierarchy use traits’ trait\_initialize without touching the rest?

And is the block evaluated every time one calls #foo, or only once?

One last question: does trait provide some mechanism to create #==,  
#hash and  
#eql?, and if so, are they static-ish (only considering instance  
variables/traits at the moment they were created) or dynamic (taking  
into  
account traits defined later)? I hesitated about which one would be  
better,  
and finally added both to SuperClass, but maybe there’s something  
for/against  
one of them.

Thanks,

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 2, 2006, 5:14am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/6 "2006-06-02T05:14:41Z")

</div>

Mauricio F. wrote:

> the Hash doesn’t preserve the order; maybe  
> [snip]

That’s another example of why I would like a data structure  
that 1) had a convenient notation for literals and 2) was  
“like” a Hash, but ordered.

Hal

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 2, 2006, 5:57am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/7 "2006-06-02T05:57:31Z")

</div>

Hal F. wrote:

> That’s another example of why I would like a data structure  
> that 1) had a convenient notation for literals and 2) was  
> “like” a Hash, but ordered.

Facet’s has Association which gives one something quite like that.

[:a \>\> 1, :b \>\> 2]

Of course it does take over the #\>\> operator, so it can’t be used  
inside any class that defines it. But that’s not a big deal. It just  
means you can’t _extend_ the following classes with code that uses an  
Association.

Bignum  
Fixnum  
Date  
IPAddr  
Process::Status

T.

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 2, 2006, 6:40am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/8 "2006-06-02T06:40:14Z")

</div>

On Fri, 2 Jun 2006 removed\_email\_address@domain.invalid wrote:

> Of course it does take over the #\>\> operator, so it can’t be used  
> T.  
> that just gave me an idea:

```
 harp:~ > cat a.rb
 require 'arrayfields'
 class Map < Array
   class Pair < Array; end
   def initialize *pairs
     fields = []
     pairs.each{|k, v| self << v and fields << k}
     self.fields = fields
   end
   def self.[](*a, &b) new(*a, &b) end
 end
 class Symbol
   def >(value) Map::Pair[self, value] end
 end
 def Map(*a, &b) Map.new(*a, &b) end
 def map(*a, &b) Map.new(*a, &b) end

 m = map :a > 4, :b > 2
 p m
 p m[:a]
 p m[:b]
 p m.to_hash
 p m.keys

 harp:~ > ruby -r rubygems a.rb
 [4, 2]
 4
 2
 {:b=>2, :a=>4}
 [:a, :b]

```

what do you think?

-a

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 1, 2006, 7:38pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/9 "2006-06-01T19:38:23Z")

</div>

On Fri, 2 Jun 2006, Mauricio F. wrote:

> traits-0.9.1.rb’s ~700 lines of code 🙂 After a cursory look, it’s clear  
> traits and SuperClass are in different leagues. SuperClass goes for minimalism  
> and meta-programming self-restraint (no methods added to core classes, no  
> hooks used…); traits seems to do so much more and pays the cost (I can see a  
> load of methods/instance variables being added at Object’s level,  
> Object.singleton\_method\_added, etc.).

all true. traits does alot. in particular it gives ‘pols’ semantics to  
default values inherited via include or normal inheritence - something  
which  
is actually tricky to do in ruby.

> Plain instance variables are the main appeal of SuperStruct or SuperClass.  
> yes.

> > ```
> > trait :foo => 1
> > 
> > ```
> 
> Interesting. Can this be made to work if X is defined as  
> class X  
> attr\_reader :foo  
> def initialize(foo); @foo = foo end  
> end  
> and doesn’t include TraitInit, or when it does something non-trivial in  
> #initialize? In other words, is it possible to have a single class in the  
> hierarchy use traits’ trait\_initialize without touching the rest?

yes. trait\_initialize is just a hook to do this

def initialize \*argv  
trait\_init \*argv  
end

so any class may just use trait\_init directly.

> And is the block evaluated every time one calls #foo, or only once?

only once. you can do

trait ‘t’ =\> ‘simple\_default\_value’

or

trait(‘t’){ ‘default\_deferred\_evaluated\_in\_context\_of\_self’ }

> One last question: does trait provide some mechanism to create #==, #hash  
> and #eql?, and if so, are they static-ish (only considering instance  
> variables/traits at the moment they were created) or dynamic (taking into  
> account traits defined later)?

one neat thing about traits is that they are remembered dynamically and  
in the  
order defined. eg.

class C  
trait ‘a’  
trait ‘b’  
class\_trait ‘c’  
end

p C.traits #=\> [[‘a’, ‘a=’], [‘b’, ‘b=’]]  
p C.rtraits #=\> [‘a’, ‘b’]

p C.class\_traits #=\> [[‘c’, ‘c=’]]  
p C.class\_rtraits #=\> [‘c’]

so it’s trival do do

module TraitsEqual  
def eql other  
to\_hash.eql other.to\_hash  
end  
def to\_hash  
self.class.rtraits.inject({}){|h,t| h.update t =\> send(t)}  
end  
end

> I hesitated about which one would be better, and finally added both to  
> SuperClass, but maybe there’s something for/against one of them.

it’s totally dynamic in traits - eg i go all the way up the chain and  
include  
any traits added later. it is a tough choice. for my use case i wanted  
this:

module Properites  
‘width’ =\> 42  
‘height’ =\> 42  
end

class C  
include Properties  
trait(‘size’){ width \* height }

```
 # this gets width, height, and size
 def to_hash
   self.class.rtraits.inject({}){|h,t| h.update t => send(t)}
 end

```

end

but i could see one going either way

> Thanks,

sure. it’s all fun stuff eh?

cheers.

-a

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 2, 2006, 10:13am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/10 "2006-06-02T10:13:05Z")

</div>

On Jun 1, 2006, at 11:13 PM, Hal F. wrote:

> [snip]
> 
> That’s another example of why I would like a data structure  
> that 1) had a convenient notation for literals and 2) was  
> “like” a Hash, but ordered.
> 
> Hal

This is why I kind of like how in Perl =\> is just a synonym for comma  
(it is in ruby too, at least for Hash literals, the problem being  
that it forces a hash literal). then

def f(\*args)  
args  
end

f(1 =\> 2) #=\> [1,2]

if you wanted a hash you could just do

def g(\*args)  
Hash[\*args]  
end

Of course this takes away your ability to write things like

f(1, 2, :option =\> value)

but you could still do

f(1, 2, {:option =\> value })

I dunno. Maybe just use caller and some evil read the file in again  
(or SCRIPT\_LINES\_\_ to find out what order they called it in).

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 3, 2006, 1:26am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/11 "2006-06-03T01:26:48Z")

</div>

Daniel S. wrote:

> hash from scratch, and use it all the places we currently use a hash.
> 
> Wait…

What is your point? Please elaborate…

Hal

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 2, 2006, 12:21pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/12 "2006-06-02T12:21:27Z")

</div>

Hal F. wrote:

> That’s another example of why I would like a data structure  
> that 1) had a convenient notation for literals and 2) was  
> “like” a Hash, but ordered.

Wow, it would be great if we then could use #to\_hash to determine  
whether an object is a hash, and then not require that the return value  
of that method be an instance of Hash. Then we could create an ordered  
hash from scratch, and use it all the places we currently use a hash.

Wait…

Daniel

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 3, 2006, 8:15am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/13 "2006-06-03T08:15:32Z")

</div>

removed\_email\_address@domain.invalid wrote:

> > [:a \>\> 1, :b \>\> 2]  
> > Process::Status  
> > fields = []
> 
> ```
> [4, 2]
> 4
> 2
> {:b=>2, :a=>4}
> [:a, :b]
> 
> ```
> 
> what do you think?

Cool. Pair is a lot like Association but you’ve added the Map class  
here. Of course you’ve limited yourself to symbol keys by using \>.  
Using Associations does have some limitations as far as being a full  
fledged omap, since it’s just an Array of Associations, but it would be  
easy enough to combine it with your map class. Put the two together and  
have:

m = map :a\>\>4, :b\>\>2

Nice thing about Associations too is that have some other uses as well.  
The only thing that would be better is a literal form and perhaps a  
slighlty better operator.

T.

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 5, 2006, 10:14pm UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/14 "2006-06-05T22:14:19Z")

</div>

On Fri, Jun 02, 2006 at 02:35:26AM +0900, removed\_email\_address@domain.invalid wrote:

> > and doesn’t include TraitInit, or when it does something non-trivial in  
> > #initialize? In other words, is it possible to have a single class in the  
> > hierarchy use traits’ trait\_initialize without touching the rest?
> 
> yes.  
> […]
> 
> > And is the block evaluated every time one calls #foo, or only once?
> 
> only once.  
> […]

Thanks for taking the time to answer my questions; it seems traits is  
very  
well-behaved indeed 🙂

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 6, 2006, 12:01am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/15 "2006-06-06T00:01:27Z")

</div>

Logan C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> This is why I kind of like how in Perl =\> is just a synonym for comma  
> (it is in ruby too, at least for Hash literals, the problem being  
> that it forces a hash literal). then

I stopped using Perl when I started using Ruby, but I seem to recall  
that =\> in Perl does more than comma. E.g. {a =\> 1, b =\> 2} is mostly  
equivalent to {‘a’, 1, ‘b’, 2}.

Ruby doesn’t do the magic quoting.

Steve

---

<div class="post-metadata">

**Author:** ![tulkas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/5daacb/32.png) [@tulkas](https://www.ruby-forum.com/u/tulkas)\
**Post date:** [June 6, 2006, 5:32am UTC](https://www.ruby-forum.com/t/an-alternative-to-the-class-foo-struct-new-vars-idiom-and/62202/16 "2006-06-06T05:32:24Z")

</div>

On Jun 5, 2006, at 5:59 PM, Steven L. wrote:

> Steve

True, but in perl you have to “force” the evaluation of variables  
anyway. =\> auto-quoting only works for barewords (\w+), as soon as  
you do something like “Hello, world” =\> 1 it’s exactly the same as  
“Hello, world”, 1

Whether or not it turns into a hash or an array is of course  
dependant on the left-hand side.

%hash = ( “a” =\> 1 );  
@array = ( “a” =\> 1 );

Which I think may as well be equivalent to ruby’s

{ “a” =\> 1 }  
[“a” =\> 1]

But (un?)fortunately they are not.

[“a” =\> 1] in ruby is [{ “a” =\> 1 }]

In fact in ruby =\> isn’t equiv to comma, it’s more like comma is  
equiv to =\> when surrounded by { }.

Getting way off topic here.
