# Ruby-Traits 0.2 released (sorry long)

**URL:** <https://www.ruby-forum.com/t/ruby-traits-0-2-released-sorry-long/118105>\
**Category:** Ruby\
**Created:** [October 23, 2007, 10:17pm UTC](https://www.ruby-forum.com/t/ruby-traits-0-2-released-sorry-long/118105 "2007-10-23T22:17:21Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![flatekmonkey](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/e8c25b/32.png) [@flatekmonkey](https://www.ruby-forum.com/u/flatekmonkey)\
**Post date:** [October 23, 2007, 10:17pm UTC](https://www.ruby-forum.com/t/ruby-traits-0-2-released-sorry-long/118105/1 "2007-10-23T22:17:21Z")

</div>

Hi list

after some very interesting input I decided to rewrite Ruby-Traits  
completely.

[http://rubyforge.org/frs/?group\_id=4642&release\_id=15737](http://rubyforge.org/frs/?group_id=4642&release_id=15737)

I have decided to implement two different kinds of traits:

- ruby-traits  
and
- pure-traits.

In detail:

- ruby-traits are mimicking some of the properties of traits but violate  
the  
flattening property. They implement some of the more dynamic features  
of modules and are in fact module based. The code is heavily influenced  
by Thomas S.‘s traits from Facets. Many thanks to Thomas for the  
permission to use his code. Note that Thomas’ traits of Facets is yet  
another  
different beast.

- pure-traits implement traits in the strict sense of their definition  
here:  
[http://portal.acm.org/ft\_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102](http://portal.acm.org/ft_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102)

They obey the flattening property, using a trait is exactly as defining  
its methods inline, no modules are used and inheritance is unchanged.  
All trait combination rules are obeyed (associative, communative, e.g.)

The main purpose of pure-traits is to play around with them and to see  
the  
benefits and shortcomings of traits based design.

The syntax has changed, again inspired by Factes, trait aliasing is done  
via #\* now, thus traits aliased and combined can be expressed more  
naturally:  
t1 \* { :t1\_a =\> :a } + t2 \* { :t2\_a =\> :a }  
works now as expected.

In addition to the traditional trait operations +, - and \*, I have  
implemented & to allow of selective usage of methods.  
I believe that the usage of this is normally a bad sign for the design  
but sometimes it might be a handy feature.

* * *

```
           Pure Traits

```

* * *

# Traits are Composable Units of Behavior. they are described here in

detail

# The interested can look here

# 

[http://portal.acm.org/ft\_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102](http://portal.acm.org/ft_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102)

# for a detailed description.

# 

# For the Rubyist Traits can be explained in some short phrases quite

effectively:

# 

# \* Traits are a Collection of Composable Behavior (e.g. methods)

# They ressemble a lot to modules.

```
t1 = trait{ def a; 42 end }
assert_kind_of Trait, t1
t2 = Trait::new { def b; 46 end }

```

# \* Traits can be composed by operations as + (union), &

(intersection), \* (aliasing)

# and - (substraction). The result of such a trait composition is

always a new trait.

# As a matter of fact traits are immutable( with the exception of

metaprogramming techniques ).  
t3 = t1 + t2  
assert\_kind\_of Trait, t3  
c1 = Class::new {  
use t3  
}  
assert\_equal 42, c1.new.a  
assert\_equal 46, c1.new.b

# \* When a trait is composed _and only in that case_ conflicts might

occur. Conflicts

# can only occur during trait unification (that is +) in case the two

unified

# traits contain methods with the same name, these methods are

replaced by conflict

# raising methods. It is the responsability of the using entity

(Module, Trait or Class)

# to resolve the conflict.

```
t4 = Trait::new do
  def a; :t4 end
end
t5 = Trait::new do
  def a; :t5 end
end
c1 = Class::new do
  use t4, t5 ### this is exactly the same as "use t4 + t5"
end
c2 = Class::new do
  use t4
  use t5 ### This is *not* the same as the above
end
assert_raise TraitsConflict do
  c1.new.a
end
assert_equal :t5, c2.new.a

```

# The second case is distinct to the first in that a “use” of a trait is

a

# transparent operation in that the trait’s methods are just defined as

if they

# were defined in the using entity (c2 in our example above).

# Almost as if they were macroexpanded

# 

# As mentioned above it is up to the using entity to resolve such

conflicts, sometime

# such conflict resolution needs access to the conflicting methods, in

these cases

# aliasing is our friend.

```
t6 = trait do
  def the_answer; 22 end
end
t7 = trait do
  def the_answer; 20 end
end
c3 = Class::new {
  use t6 * {:first_answer => :the_answer} +
      t7 * {:second_answer=> :the_answer}
  def the_answer; first_answer + second_answer end
}
assert_equal 42, c3.new.the_answer

```

# Sometimes of course we do not want to resolve the conflict

explicitly but we just

# want to avoid it by choising from which trait we want to use the

method, again

# trait composition shall be used to achieve that task.

```
m1 = Module::new do
  use t6 + ( t7 - :the_answer )
end
assert_equal 22, Class::new{ extend m1 }.the_answer

```

# \* When traits are used they obey to the Flattening Property, that is

the using entity

# does not inherit from the trait but just get its methods defined.

# Again one can very nicely understand what is going on when

thinking of macro expansion.  
t= trait {  
def a; 1 end  
}  
c = Class::new {  
use t  
}  
o = c.new  
assert\_equal 1, o.a  
t.send :add\_method, :a do 2 end  
assert\_equal 1, o.a  
assert\_equal 1, c.new.a  
assert\_equal 2, t.to\_class.new.a

# \* Calls to super in trait methods are dynamically resolved at

runtime, as is the case

# for modules.

```
t8 = trait { def a
 super * 7 end }
c4 = Class::new { def a; 3 end }
c5 = Class::new( c4 ) {
  use t8
}
assert_equal 21, c5.new.a

```

# Again the flattening property can be tested with the semantics of

super, the usage of the trait

# just defines methods, they can be replaced with methods in the class

later, but they are not

# accessible via super, as they were if they had been included via

modules.  
c5.module\_eval do  
def a; super.succ end  
end  
assert\_equal 4, c5.new.a

* * *

```
           Ruby Traits

```

* * *

# Traits are Composable Units of Behavior. they are described here in

detail

# The interested can look here

# 

[http://portal.acm.org/ft\_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102](http://portal.acm.org/ft_gateway.cfm?id=1028771&type=pdf&coll=GUIDE&dl=GUIDE&CFID=7912496&CFTOKEN=77115102)

# for a detailed description.

# 

# For the Rubyist Traits can be explained in some short phrases quite

effectively:

# 

# \* Traits are a Collection of Composable Behavior (e.g. methods)

# The ressemble a lot to modules.

```
t1 = trait{ def a; 42 end }
assert_kind_of Trait, t1
t2 = Trait::new { def b; 46 end }

```

# \* Traits can be composed by operations as + (union), &

(intersection), \* (aliasing)

# and - (substraction). The result of such a trait composition is

always a new trait.

# As a matter of fact traits are immutable( with the exception of

metaprogramming techniques ).  
t3 = t1 + t2  
assert\_kind\_of Trait, t3  
c1 = Class::new {  
use t3  
}  
assert\_equal 42, c1.new.a  
assert\_equal 46, c1.new.b

# \* When a trait is composed _and only in that case_ conflicts might

occur. Conflicts

# can only occur during trait unification (that is +) if and only if

the two unified

# traits contain methods with the same name, these methods are

replaced by conflict

# raising methods. It is the responsability of the using entity

(Module, Trait or Class)

# to resolve the conflict.

```
t4 = Trait::new do
  def a; :t4 end
end
t5 = Trait::new do
  def a; :t5 end
end
c1 = Class::new do
  use t4, t5 ### this is exactly the same as "use t4 + t5"
end
c2 = Class::new do
  use t4
  use t5 ### This is *not* the same as the above
end
assert_raise TraitsConflict do
  c1.new.a
end
assert_equal :t5, c2.new.a

```

# The second case is distinct to the first in that a “use” of a trait is

a

# transparent operation in which the trait’s methods are just defined as

if they

# were defined in the using entity (c2 in our example above).

# 

# As mentioned above it is up to the using entity to resolve such

conflicts, sometime

# such conflict resolution needs access to the conflicting methods, in

these cases

# aliasing is our friend.

```
t6 = trait do
  def the_answer; 22 end
end
t7 = trait do
  def the_answer; 20 end
end
c3 = Class::new {
  use t6 * {:the_answer=>:first_answer} +
      t7 * {:the_answer=>:second_answer}
  def the_answer; first_answer + second_answer end
}
assert_equal 42, c3.new.the_answer

```

# Sometimes of course we do not want to resolve the conflict

explicitly but we just

# want to avoid it by choising from which trait we want to use the

method, again

# trait composition shall be used to achieve that task.

```
m1 = Module::new do
  use t6 + ( t7 - :the_answer )
  def the_answer; super.to_s.to_i(20) end
end
assert_equal 42, Class::new{ extend m1 }.the_answer

```

# \* When traits are used they obey to the Flattening Property, that is

the using entity

# does not inherit from the trait but just get its methods defined

exactly as if the defs

# of the trait were macro expanded into the using entity.

# This however is something I have not implemented in ruby-traits

(only in pure-traits).

# As one can notice in the super example above the method

t6#the\_answer can be accessed via

# super in the method m1#the\_answer

# There are two reasons for this, (a) I wanted to use Thomas’

elegant and simple approach

# and (b) this is a behaviour Rubyists are rather fond of, so I

really thaught that

# it might be a good idea to do this. The price to pay is that

traits still behave a little

# bit too much as Modules, the following example shows the down side

of this approach  
t= trait {  
def a; 1 end  
}  
c = Class::new {  
use t  
}  
assert c \< t  
o = c.new  
assert\_equal 1, o.a  
t.send :add\_method, :a do 2 end  
assert\_equal 2, o.a

# Another downside of this is that Trait#define\_method,

Trait#remove\_method and friends

# cannot be undefined, using them on traits directly would however

endanger correct

# conflict detection or trigger false conflicts!

# In order to do correct traits metaprogramming Traits#add\_method and

Traits#del\_method,

# both are private, shall be used.

# \* Calls to super in trait methods are dynamically resolved at

runtime, as is the case

# for modules.

# This even works together with the usage of super as shown above

```
t8 = trait { def a; super * 7 end }
c4 = Class::new { def a; 3 end }
c5 = Class::new( c4 ) {
  use t8
  def a; super * 2 end
}
assert_equal 42, c5.new.a

```

# 

```
# Trait#to_class simply is a convenience method that
# simply creates an anonymous class from this trait.

```

“t.to\_class(parent=Object)” is short for  
# “Class::new(parent)”{ use t }  
t9 = trait { def a; :a9 end; def b; :b9 end }  
t10 = trait { def b; :b10 end; def c; :c10 end }  
c6 = ( t9 + t10 ).to\_class  
assert\_equal :a9, c6.new.a  
assert\_equal :c10, c6.new.c  
assert\_raise TraitsConflict do c6.new.b end

---

<div class="post-metadata">

**Author:** ![flatekmonkey](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/e8c25b/32.png) [@flatekmonkey](https://www.ruby-forum.com/u/flatekmonkey)\
**Post date:** [October 24, 2007, 1:06pm UTC](https://www.ruby-forum.com/t/ruby-traits-0-2-released-sorry-long/118105/2 "2007-10-24T13:06:07Z")

</div>

On Oct 23, 4:16 pm, “Robert D.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> t1 \* { :t1\_a =\> :a } + t2 \* { :t2\_a =\> :a }  
> works now as expected.
> 
> In addition to the traditional trait operations +, - and \*, I have  
> implemented & to allow of selective usage of methods.  
> I believe that the usage of this is normally a bad sign for the design  
> but sometimes it might be a handy feature.

[snip]

Whew! Yep, long, but interesting. I’ll have to check the ruby-traits  
code and see if there’s any cross-pollination to be had. Seems like  
maybe the main difference between this and Facets is the use of the  
Traits \< Module class (where as Facets just extends Module). I’m also  
curious about the & method.

Great work!

T.

---

<div class="post-metadata">

**Author:** ![flatekmonkey](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/e8c25b/32.png) [@flatekmonkey](https://www.ruby-forum.com/u/flatekmonkey)\
**Post date:** [October 24, 2007, 2:25pm UTC](https://www.ruby-forum.com/t/ruby-traits-0-2-released-sorry-long/118105/3 "2007-10-24T14:25:04Z")

</div>

On 10/24/07, Trans [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > - ruby-traits
> > 
> > The syntax has changed, again inspired by Factes, trait aliasing is done  
> > [snip]
> 
> Whew! Yep, long, but interesting. I’ll have to check the ruby-traits  
> code and see if there’s any cross-pollination to be had. Seems like  
> maybe the main difference between this and Facets is the use of the  
> Traits \< Module class (where as Facets just extends Module). I’m also  
> curious about the & method.
> 
> Great work!  
> Well thanks 😉  
> to make your live a little bit easier, I decided to subclass Module  
> because I needed some state for correct conflict detection and I did  
> not want to pollute the Module instance variable space.  
> AAMOF you can naively compute the conflicting methods of two modules  
> like this

m1.instance\_methods & m2.instance\_methods, however that will give  
false conflicts for the diamond shape inclusion:

m = Module::new { def a; 42 end }  
m1 = m + Module::new{}  
m2 = m + Module::new{}  
m3 = m1 + m2 ## a is not a conflict

In order to detect this I need state, at least I could not figure out  
how to do it dynamically, well walking up the ancestors array should  
work but I’d rather not go through that trouble. Hmm maybe I should…

And & is just an idea stolen from Daniel and Mauricio 😉

Cheers  
Robert
