Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[ANN] traits-0.1.0

1 view
Skip to first unread message

Ara.T.Howard

unread,
May 9, 2005, 6:47:09 PM5/9/05
to
URLS

http://raa.ruby-lang.org/search.rhtml?search=traits
http://codeforpeople.com/lib/ruby/traits

ABOUT

traits.rb aims to be a better set of attr_* methods and encourages better
living through meta-programming and uniform access priciples. traits.rb
supercedes attributes.rb. why? the name is shorter ;-)

HISTORY

0.1.0

completely reworked impl so NO parsing of inspect strings is required -
it's all straight methods (albeit quite confusing ones) now. the
interface is unchanged.

0.0.0

initial version


AUTHOR

ara [dot] t [dot] howard [at] noaa [dot] gov

SAMPLES

<========< sample/a.rb >========>

~ > cat sample/a.rb

require 'traits'
#
# defining a trait is like attr_accessor in the simple case
#
class C
trait :t
end

o = C::new
o.t = 42
p o.t

#
# and can be made even shorter
#

class B; has :x; end

o = B::new
o.x = 42
p o.x


~ > ruby sample/a.rb

42
42


<========< sample/b.rb >========>

~ > cat sample/b.rb

require 'traits'
#
# multiple traits can be defined at once using a list/array of string/sybmol
# arguments
#
class C
has :t0, :t1
has %w( t2 t3 )
end

obj = C::new
obj.t0 = 4
obj.t3 = 2
print obj.t0, obj.t3, "\n"

~ > ruby sample/b.rb

42


<========< sample/c.rb >========>

~ > cat sample/c.rb

require 'traits'
#
# a hash argument can be used to specify default values
#
class C
has 'a' => 4, :b => 2
end

o = C::new
print o.a, o.b, "\n"

#
# and these traits are smartly inherited
#
class K < C; end

o = K::new
o.a = 40
p( o.a + o.b ) # note that we pick up a default b from C class here since it
# has not been set

o.a = 42
o.b = nil
p( o.b || o.a ) # but not here since we've explicitly set it to nil

~ > ruby sample/c.rb

42
42
42


<========< sample/d.rb >========>

~ > cat sample/d.rb

require 'traits'
#
# all behaviours work within class scope (metal/singleton-class) to define
# class methods
#
class C
class << self
traits 'a' => 4, 'b' => 2
end
end

print C::a, C::b, "\n"

#
# singleton methods can even be defined on objects
#

class << (a = %w[dog cat ostrich])
has 'category' => 'pets'
end
p a.category

#
# and modules
#
module Mmmm
class << self; trait 'good' => 'bacon'; end
end

p Mmmm.good

~ > ruby sample/d.rb

42
"pets"
"bacon"


<========< sample/e.rb >========>

~ > cat sample/e.rb

require 'traits'
#
# shorhands exit to enter 'class << self' in order to define class traits
#
class C
class_trait 'a' => 4
c_has :b => 2
end

print C::a, C::b, "\n"

~ > ruby sample/e.rb

42


<========< sample/f.rb >========>

~ > cat sample/f.rb

require 'traits'
#
# as traits are defined they are remembered and can be accessed
#
class C
class_trait :first_class_method
trait :first_instance_method
end

class C
class_trait :second_class_method
trait :second_instance_method
end

#
# readers and writers are remembered separatedly
#
p C::class_reader_traits
p C::instance_writer_traits

#
# and can be gotten together at class or instance level
#
p C::class_traits
p C::traits

~ > ruby sample/f.rb

["first_class_method", "second_class_method"]
["first_instance_method=", "second_instance_method="]
[["first_class_method", "second_class_method"], ["first_class_method=", "second_class_method="]]
[["first_instance_method", "second_instance_method"], ["first_instance_method=", "second_instance_method="]]


<========< sample/g.rb >========>

~ > cat sample/g.rb

require 'traits'
#
# another neat feature is that they are remembered per hierarchy
#
class C
class_traits :base_class_method
trait :base_instance_method
end

class K < C
class_traits :derived_class_method
trait :derived_instance_method
end

p C::class_traits
p K::class_traits

~ > ruby sample/g.rb

[["base_class_method"], ["base_class_method="]]
[["derived_class_method", "base_class_method"], ["derived_class_method=", "base_class_method="]]


<========< sample/h.rb >========>

~ > cat sample/h.rb

require 'traits'
#
# a depth first search path is used to find defaults
#
class C
has 'a' => 42
end
class K < C; end

k = K::new
p k.a

#
# once assigned this is short-circuited
#
k.a = 'forty-two'
p k.a

~ > ruby sample/h.rb

42
"forty-two"


<========< sample/i.rb >========>

~ > cat sample/i.rb

require 'traits'
#
# getters and setters can be defined separately
#
class C
has_r :r
end
class D
has_w :w
end

#
# defining a reader trait still defines __public__ query and __private__ writer
# methods
#
class C
def using_private_writer_and_query
p r?
self.r = 42
p r
end
end
C::new.using_private_writer_and_query

#
# defining a writer trait still defines __private__ query and __private__ reader
# methods
#
class D
def using_private_reader
p w?
self.w = 'forty-two'
p w
end
end
D::new.using_private_reader

~ > ruby sample/i.rb

false
42
false
"forty-two"


<========< sample/j.rb >========>

~ > cat sample/j.rb

require 'traits'
#
# getters delegate to setters iff called with arguments
#
class AbstractWidget
class_trait 'color' => 'pinky-green'
class_trait 'size' => 42
class_trait 'shape' => 'square'

trait 'color'
trait 'size'
trait 'shape'

def initialize
color self.class.color
size self.class.size
shape self.class.shape
end
def inspect
"color <#{ color }> size <#{ size }> shape <#{ shape }>"
end
end

class BlueWidget < AbstractWidget
color 'blue'
size 420
end

p BlueWidget::new

~ > ruby sample/j.rb

color <blue> size <420> shape <square>


<========< sample/k.rb >========>

~ > cat sample/k.rb

require 'traits'
#
# the rememberance of traits can make generic intializers pretty slick
#
class C
#
# define class traits with defaults
#
class_traits(
'a' => 40,
'b' => 1,
'c' => 0
)

#
# define instance traits whose defaults come from readable class ones
#
class_rtraits.each{|ct| instance_trait ct => send(ct)}

#
# any option we respond_to? clobbers defaults
#
def initialize opts = {}
opts.each{|k,v| send(k,v) if respond_to? k}
end

#
# show anything we can read
#
def inspect
self.class.rtraits.inject(0){|n,t| n += send(t)}
end
end

c = C::new 'c' => 1
p c

~ > ruby sample/k.rb

42


<========< sample/l.rb >========>

~ > cat sample/l.rb

require 'traits'
#
# even defining single methods on object behaves
#
a = []

class << a
trait 'singleton_class' => class << self;self;end

class << self
class_trait 'x' => 42
end
end

p a.singleton_class.x

~ > ruby sample/l.rb

42


CAVEATS

this library is experimental and subject to (eg. will) change.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================

benny

unread,
May 9, 2005, 9:21:59 PM5/9/05
to
Ara.T.Howard wrote:

>
> ABOUT
>
> traits.rb aims to be a better set of attr_* methods and encourages
> better
> living through meta-programming and uniform access priciples.
> traits.rb
> supercedes attributes.rb. why? the name is shorter ;-)
>

that looks great!!

no need for class-attributes / metaclasses anymore, as it seems.
if lib and usage is stable we only have to convince matz.
definitely a candidate for ruby 2.0 / rite.


benny

"Peña, Botp"

unread,
May 9, 2005, 10:40:31 PM5/9/05
to
Ara.T.Howard [mailto:Ara.T....@noaa.gov] wrote:
#Subject: [ANN] traits-0.1.0
#

cool. worth adding to ruby.
thanks for traits.

kind regards -botp


Ara.T.Howard

unread,
May 10, 2005, 12:15:17 PM5/10/05
to

i'm having quite a time deciding what to do with traits. i first released as
'attributes' but some complained that

attribute 'foo'

and

class_attribute 'bar'

were just too long. to remedy that i switched to 'trait' - a synonym for
attribute. however, as it's been pointed out, that name currently has a
meaning in cs to some people. my current thoughts are

random thoughts for traits/against attributes:

- trait is short

- traits is a synonym for attribute (attr, attr_accessor, etc)

- i like the word 'role' to describe what others are calling traits. the
perl6 guys use this too so any future impl of 'traits' (the other ones)
as 'roles' wouldn't likely suprise anyone

- 'traits' (the other ones) are of dubious value to ruby. it's been shown
that they can be easily implemented in ruby - yet no one is using them.
their value, to me, seems largely academic and smells of
hyper-abstraction (read obfusication). however, i can easily imagine
situations where they might be extremely appropriate and wouldn't want
to steal the name. does anyone who might plan on needing it object to
using 'roles' for that concept?

random thoughts for attributes/against traits

- no confusion with other traits

- the alias 'has' can make 'attribute' plenty short (the current version
of traits uses this alias too btw.)

one other thing, the impl of traits was suprisingly hard. the tricky bit was
implementing defaults and inheritence in the general case of class methods,
instance methods, singleton methods (on objects not classes, and module
methods. the difficult bits revolved around being able to these things

singleton_super

class C
class << self
p singleton_super #=> C
end
end

class << []
p singleton_super #=> <#Array:1234567>
end

detecting singleton-ness

class C
p singleton? #=> false
class << self
p singleton? #=> true
end
end

p singleton? #=> false

class << []
p singleton? #=> true
end

deciding where to look for defaults

class A
trait 'x' => 42
end
class B < A
trait 'x' # clearly our default comes from A
end

module M
traits 'x' => 42
end
class C
include M # clearly our def AND default comes from A
end

a = []
class << a
trait 'foo' => 'bar' # our defaults must come from ourselves (no
# inheritence)
end

class A
class_trait 'x' => 42
trait 'x' => 'forty-two'
end
class B < A
# clearly get def and default of class x from A
# clearly get def and default of __instance__ x from A!
end

b = B::new
b.x = nil
p b.x # don't get default from A now!


anyhow - these are the kinds of confusing things anyone reading the code
will see being addressed.

and any code review would be appreciated. the code is pretty non-trivial and
un-commented - but it is brief. you'd need a complete understanding of
singleton (or whatever) classes to review it. one thing i plan on doing is
pulling alot of the __trait_XXX methods out of Object and into a specialized
module to avoid polluting the Object namespace : the current approach of
prefacing everything with __trait_XXX was just to get it working. feel free
to ping my offline.

any comments appreciated. sorry for confusion - i generally don't have a hard
time coming up with a decent name for a project but this one's stumped me.
people have expressed interest in me gem-izing traits so i'd like to pin it
down a bit before doing so.

kind regards.

ps. urls for project:

http://raa.ruby-lang.org/search.rhtml?search=traits
http://codeforpeople.com/lib/ruby/traits

Berger, Daniel

unread,
May 10, 2005, 12:55:54 PM5/10/05
to
> -----Original Message-----
> From: Ara.T.Howard [mailto:Ara.T....@noaa.gov]
> Sent: Tuesday, May 10, 2005 10:35 AM
> To: ruby-talk ML
> Subject: [RFC] traits-0.1.0

> - i like the word 'role' to describe what others are
> calling traits. the
> perl6 guys use this too so any future impl of 'traits'
> (the other ones)
> as 'roles' wouldn't likely suprise anyone

That seems reasonable.

> - 'traits' (the other ones) are of dubious value to
> ruby. it's been shown
> that they can be easily implemented in ruby - yet no
> one is using them.
> their value, to me, seems largely academic and smells of
> hyper-abstraction (read obfusication).

For Ruby they would only be useful where you want to mixin different
modules with identical methods, while needing access to a specific
access to a particular module's method that would otherwise have been
overwritten. Apparently this is such a rare occurrence that no one
worries about it and/or works around it for those times when it does
occur.

Unless anyone objects, you should keep your "traits" package the way it
is, and those other traits will be referred to as "roles" in Ruby
(should anyone implement them and release it as a package and/or
integrate it into the Ruby core).

Regards,

Dan


Ara.T....@noaa.gov

unread,
May 10, 2005, 3:00:49 PM5/10/05
to
On Wed, 11 May 2005, Berger, Daniel wrote:

>> -----Original Message-----
>> From: Ara.T.Howard [mailto:Ara.T....@noaa.gov]=20
>> Sent: Tuesday, May 10, 2005 10:35 AM
>> To: ruby-talk ML
>> Subject: [RFC] traits-0.1.0
>

>> - i like the word 'role' to describe what others are=20
>> calling traits. the
>> perl6 guys use this too so any future impl of 'traits'=20


>> (the other ones)
>> as 'roles' wouldn't likely suprise anyone
>
> That seems reasonable.
>

>> - 'traits' (the other ones) are of dubious value to=20


>> ruby. it's been shown

>> that they can be easily implemented in ruby - yet no=20


>> one is using them.
>> their value, to me, seems largely academic and smells of
>> hyper-abstraction (read obfusication).
>
> For Ruby they would only be useful where you want to mixin different
> modules with identical methods, while needing access to a specific
> access to a particular module's method that would otherwise have been
> overwritten. Apparently this is such a rare occurrence that no one
> worries about it and/or works around it for those times when it does
> occur.

my thoughts exactly.

> Unless anyone objects, you should keep your "traits" package the way it
> is, and those other traits will be referred to as "roles" in Ruby
> (should anyone implement them and release it as a package and/or
> integrate it into the Ruby core).

yay! +1 for less coding ;-)

Ilias Lazaridis

unread,
May 10, 2005, 5:06:01 PM5/10/05
to
Ara.T.Howard wrote:
>
> i'm having quite a time deciding what to do with traits. i first
> released as 'attributes' but some complained that
>
> attribute 'foo'
>
> and
>
> class_attribute 'bar'
>
> were just too long. to remedy that i switched to 'trait' - a synonym
> for attribute. however, as it's been pointed out, that name
> currently has a meaning in cs to some people. my current thoughts
> are
>
> random thoughts for traits/against attributes:
>
> - trait is short

and used within C++

> - traits is a synonym for attribute (attr, attr_accessor, etc)

no need to use a synonym.

[...]

> random thoughts for attributes/against traits
>
> - no confusion with other traits

yes

> - the alias 'has' can make 'attribute' plenty short (the current
> version of traits uses this alias too btw.)

yes

> one other thing, the impl of traits was suprisingly hard. the tricky

[...]

The code fragments (usage) I've saw are not thus attractive.

Code should looks simpler, more 'natural'.

-

This is an important project, but should be setup collaborative.

So, if you setup a ruby-forge project, people can contribute.

call it "attributes" or "attrib" or "has" - but not "traits".

.

--
http://lazaridis.com

Ara.T....@noaa.gov

unread,
May 10, 2005, 5:46:43 PM5/10/05
to
On Wed, 11 May 2005, Ilias Lazaridis wrote:

>> - trait is short
>
> and used within C++

hmm.

>> - traits is a synonym for attribute (attr, attr_accessor, etc)
>
> no need to use a synonym.

i mean it's meaning is the similar to 'attr :a == trait :a'.

> [...]
>
>> random thoughts for attributes/against traits
>>
>> - no confusion with other traits
>
> yes

but are the other traits being used? also these seem to be called roles in
some langs too... this is a valid concern though.

>> - the alias 'has' can make 'attribute' plenty short (the current version of
>> traits uses this alias too btw.)
>
> yes
>
>> one other thing, the impl of traits was suprisingly hard. the tricky
> [...]
>
> The code fragments (usage) I've saw are not thus attractive.
>
> Code should looks simpler, more 'natural'.

what do you think could be more natural than

class C
has 'a' => 42
end

c = C::new
p c.a #=> 42

or

class AbstractWidget
class << self
has 'color'
has 'width'
has 'height'
end
end

class SmallishBlueWidget
color 'blue'
width 100
height 42
end

??

it's the best i could manage. come up with something more natural and i'll
see what i can do to implement.

> This is an important project, but should be setup collaborative.

i'm working 70+ hours per week already - but if someone wants to take over and
do the initial setup work it's fine with me.

> So, if you setup a ruby-forge project, people can contribute.

this is welcome of course - but see above.

> call it "attributes" or "attrib" or "has" - but not "traits".

+1 for attributes then.

cheers.

Ilias Lazaridis

unread,
May 11, 2005, 9:13:37 PM5/11/05
to
Ara.T....@noaa.gov wrote:
> On Wed, 11 May 2005, Ilias Lazaridis wrote:
>
>>> - trait is short
>>
>> and used within C++
>
> hmm.
>
>>> - traits is a synonym for attribute (attr, attr_accessor, etc)
>>
>> no need to use a synonym.
>
> i mean it's meaning is the similar to 'attr :a == trait :a'.

I mean: no mean to use (and search) a synonym

>> [...]
>>
>>> random thoughts for attributes/against traits
>>>
>>> - no confusion with other traits
>>
>> yes
>
> but are the other traits being used? also these seem to be called roles in
> some langs too... this is a valid concern though.

again: no need to research.

>>> - the alias 'has' can make 'attribute' plenty short (the current
>>> version of traits uses this alias too btw.)
>>
>> yes
>>
>>> one other thing, the impl of traits was suprisingly hard. the tricky
>>
>> [...]
>>
>> The code fragments (usage) I've saw are not thus attractive.
>>
>> Code should looks simpler, more 'natural'.
>
>
> what do you think could be more natural than
>
> class C
> has 'a' => 42
> end

class C
a = 42
end

class C
var a = 42
end

> c = C::new
> p c.a #=> 42
>
> or
>
> class AbstractWidget

[...]

> class SmallishBlueWidget
[...]

I dislike all this, but cannot clarify why.

concept, ruby, flexibility

> it's the best i could manage. come up with something more natural and i'll
> see what i can do to implement.
>
>> This is an important project, but should be setup collaborative.
>
> i'm working 70+ hours per week already - but if someone wants to take
> over and do the initial setup work it's fine with me.

I think you should postpone this project.

>> So, if you setup a ruby-forge project, people can contribute.
>
> this is welcome of course - but see above.
>
>> call it "attributes" or "attrib" or "has" - but not "traits".
>
> +1 for attributes then.

ok

.

--
http://lazaridis.com

0 new messages