Attr Methods and object setters

We can do:

attr_accessor :bla

Now, on an object one can do this:

object.bla = ‘foo’

Or
object.bla

to retrieve the value.

I am wondering whether we could do this:

object.bla ‘foo’

This does not seem to work. My question is, why was = used, but so many
people in their ruby code also allow the last version? It usually has
this form:

object.set_bla ‘foo’

So basically I guess my question is there an attr to the second, and if
not why not?

On Jun 25, 2009, at 11:05 , Marc H. wrote:

This does not seem to work. My question is, why was = used, but so
many
people in their ruby code also allow the last version? It usually has
this form:

object.set_bla ‘foo’

no, we don’t. I’d argue strongly against “so many”. It is highly non-
idiomatic.

On Thu, Jun 25, 2009 at 11:29 AM, Ryan D.[email protected]
wrote:

On Jun 25, 2009, at 11:05 , Marc H. wrote:

This does not seem to work. My question is, why was = used, but so many
people in their ruby code also allow the last version? It usually has
this form:

object.set_bla ‘foo’

no, we don’t. I’d argue strongly against “so many”. It is highly
non-idiomatic.

Generally you’ll see the set_bla behavior in a few cases:

  1. Code from folks who, as Ryan said, aren’t writing idiomatic Ruby.
    People who come over from languages like Java or C++ are used to more
    formal accessor/mutator method pairs.

  2. Code that’s exposing a declarative DSL, e.g.

    person do
    name “John D.”
    phone “206-867-5309”
    end

Personally, I prefer to stick with simple foo = bar or thing.foo = bar
for assignment, even in DSLs.

~ j.

no, we don’t. I’d argue strongly against “so many”. It is highly non-
idiomatic.

Ruby/GTK

I guess I can hunt around which ruby-projects are using set_*
specifically just to document whether it is common or not, but I can
already see that my question is not addressed regarding the attr*
decisions.

On Jun 25, 2009, at 12:37 , Marc H. wrote:

no, we don’t. I’d argue strongly against “so many”. It is highly non-
idiomatic.

Ruby/GTK

I guess I can hunt around which ruby-projects are using set_*
specifically just to document whether it is common or not, but I can
already see that my question is not addressed regarding the attr*
decisions.

we did answer, just indirectly. The idiomatic form is #blah and #blah=.

Hi –

On Fri, 26 Jun 2009, Marc H. wrote:

no, we don’t. I’d argue strongly against “so many”. It is highly non-
idiomatic.

Ruby/GTK

I guess I can hunt around which ruby-projects are using set_*
specifically just to document whether it is common or not, but I can
already see that my question is not addressed regarding the attr*
decisions.

Do you mean something like

attr_accessor_using_set_and_get_methods :name

I’m not sure how to analyze why this isn’t in the language, since I
can’t picture it being there. I guess it’s partly because the language
supports the idea of attributes as pseudo-L-values; in other words,
when you do this:

person.name = “David”

you’re doing something that looks like an assignment, but is actually
a method call. Lots of things in Ruby look like something but are
actually method calls (like array[1] = 100, or the when clauses in a
case statement).

Also, set_name(arg) is really just another method. There’s nothing
special about it. Someone might decide to avoid writing accessor
methods and write get/set ones instead (though I discourage it), but
they might decide to write lots of different methods, and the language
can’t provide shortcuts for all of them.

David

On Thu, Jun 25, 2009 at 2:05 PM, Marc H.[email protected]
wrote:

to retrieve the value.

I am wondering whether we could do this:

object.bla ‘foo’

This is the pattern I use:

http://pastie.org/516343

Since it’s really only valuable to me when I make certain types of
DSLs, I don’t see the need for it to be in the language.
But I feel the above pattern is fairly clean.

-greg

On Fri, Jun 26, 2009 at 4:00 AM, Fabian
Streitel[email protected] wrote:

This is the pattern I use:

http://pastie.org/516343 http://pastie.org/516343

I only see one problem with that: You can’t assign nil or false to the
attribute that way.
And I have to say that’s pretty much one of the most essential features I
use – all the time :slight_smile:

Really? Can you give me an example?

See here: http://pastie.org/526403

With your example you CAN reset it to nil, but you’ll have to use the
standard getters and setters

Greetz,
k

2009/6/26 Gregory B. [email protected]

This is the pattern I use:

http://pastie.org/516343 http://pastie.org/516343

I only see one problem with that: You can’t assign nil or false to the
attribute that way.
And I have to say that’s pretty much one of the most essential features
I
use – all the time :slight_smile:

Greetz!
k

2009/6/25 Gregory B. [email protected]

Though again, do you have a real example of
when you nil out a set value? I can’t picture why I’d do that

Just imagine you’re building some sort of a binary tree structure.
You’d have inner nodes and leafs and you’d probably want
to represent the leafs with nil. Now when you remove a node
at some point, you’ll have to set the #left_child accessor (or
whatever you like to call it) to nil…

Or take an options hash which has to provide a “default” state
so the system can decide whether or not an option was explicitly
set. You’d probably want to use nil for that (at least I would :wink:

I have to say: nil is one of the nicest features of dynamically typed
languages - just imagine using java without it…
I use it all the time.

etc. etc.

def name(*args)
return @name if args.empty?
@name = args.first
end

Better, but IMHO that’s WAY too much overhead for something as basic as
a
setter.
After all, you have to construct an array everytime you access the
setter…

Greetz,
k

On Sat, Jun 27, 2009 at 10:42 AM, Fabian
Streitel[email protected] wrote:

See here: http://pastie.org/526403

With your example you CAN reset it to nil, but you’ll have to use the
standard getters and setters

Since this is not a DSL, I wouldn’t alias name= to name, I’d just
provide an attr_writer, as you’ve said here.

I see:

person.name = nil

being conceivably useful (Though again, do you have a real example of
when you nil out a set value? I can’t picture why I’d do that)

but something like

person.name(nil) is seriously ugly, and doesn’t make much sense.

Anyway, here’s a better way to solve the problem that probably
addresses your concerns:

def name(*args)
return @name if args.empty?
@name = args.first
end

name ‘foo’
=> “foo”
name
=> “foo”

name nil
=> nil
name
=> nil

name [1,2,3]
=> [1, 2, 3]

name
=> [1, 2, 3]

Fabian S. wrote:

def name(*args)
return @name if args.empty?
@name = args.first
end

Better, but IMHO that’s WAY too much overhead for something as basic as
a
setter.
After all, you have to construct an array everytime you access the
setter…

Well, have you benchmarked this? Who’s to say that the argument list
isn’t already passed in array form? Conceivably it could be more
efficient this way.

Anyway, “WAY too much overhead” makes no sense. Too much for what? What
percentage slower does your entire application run with this code? (My
guess: <1%). So if this code does what you want, and you like the way it
looks - i.e. it’s easy to maintain and pleasing to work with - then
that’s usually worth it.

Gregory B. wrote:

On Sat, Jun 27, 2009 at 4:52 PM, Fabian
Streitel[email protected] wrote:

def name(*args)
return @name if args.empty?
@name = args.first
end
Better, but IMHO that’s WAY too much overhead for something as basic as a
setter.
After all, you have to construct an array everytime you access the setter…

Huh? This is the way Ruby arguments work no matter what. Using *args
just gives you raw access to the arguments.

No, *args does construct an array.

def f1(a,b,c);end
=> nil
def f2(*args);end
=> nil
GC.start; 1000.times {f1(1,2,3)}; ObjectSpace.each_object(Array) {}
=> 2119
GC.start; 1000.times {f2(1,2,3)}; ObjectSpace.each_object(Array) {}
=> 3119
GC.start; 1000.times {f1(1,2,3)}; ObjectSpace.each_object(Array) {}
=> 2119
GC.start; 1000.times {f2(1,2,3)}; ObjectSpace.each_object(Array) {}
=> 3119

On Sat, Jun 27, 2009 at 4:52 PM, Fabian
Streitel[email protected] wrote:

so the system can decide whether or not an option was explicitly
set. You’d probably want to use nil for that (at least I would :wink:

I didn’t mean ‘when would you set an attribute to nil’

I meant, when would you ever do this with a DSL call?

Neither of the examples you mentioned address that. If you don’t need
to do this in a DSL, attr_writer / attr_accessor already work fine.

def name(*args)
return @name if args.empty?
@name = args.first
end

Better, but IMHO that’s WAY too much overhead for something as basic as a
setter.
After all, you have to construct an array everytime you access the setter…

Huh? This is the way Ruby arguments work no matter what. Using *args
just gives you raw access to the arguments.

On Sat, Jun 27, 2009 at 8:41 PM, Joel
VanderWerf[email protected] wrote:

end

Better, but IMHO that’s WAY too much overhead for something as basic as a
setter.
After all, you have to construct an array everytime you access the
setter…

Huh? This is the way Ruby arguments work no matter what. Using *args
just gives you raw access to the arguments.

No, *args does construct an array.

Interesting. Does this really matter though?
I know that GC is slow in Ruby but just how soon would this become a
problem in practical applications.

(I suppose it depends on the application)

-greg

Gregory B. wrote:

Anyway, here’s a better way to solve the problem that probably
addresses your concerns:

def name(*args)
return @name if args.empty?
@name = args.first
end

Another way to do this is to use some kind of singleton object

Nothing = Object.new
def name(value = Nothing)
@name = value unless value == Nothing
@name
end

On Jun 27, 11:26 pm, Daniel DeLorme [email protected] wrote:

Nothing = Object.new
def name(value = Nothing)
@name = value unless value == Nothing
@name
end

def name(value = Exception)
@name = value unless value == Exception
@name
end

Anyway, “WAY too much overhead” makes no sense. Too much for what? What
percentage slower does your entire application run with this code? (My
guess: <1%). So if this code does what you want, and you like the way it
looks - i.e. it’s easy to maintain and pleasing to work with - then
that’s usually worth it.

Alright, I admit, that wasn’t very differentiated from my side…
What I meant to say was:
It SEEMS/FEELS to me like useless overhead (however small) to construct
a
new array
for a setter when all you have to do is type one = more, BUT I haven’t
benchmarked
that and I don’t intend to ;-). But that’s just my POV.

If you like that method better – noones keeping you from using it. And
I
admit,
for DSLs it is pretty nice. I’d use it there.

Nothing = Object.new
def name(value = Nothing)
@name = value unless value == Nothing
@name
end

Or Daniel’s method.

But for any normal class that does not provide DSL semantics, I’d still
go
with normal
getters and setters. I just don’t see the point of reducing the amount
of my
typing by
a single =, when on the other hand I have to either construct a whole
array
each time
or introduce a new neutral element.

To mee that just doesn’t feel right, I guess…

On Sun, Jun 28, 2009 at 9:01 AM, Fabian
Streitel[email protected] wrote:

Or Daniel’s method.
I’d probably use Daniel’s method.

I’ve found Object.new to create a null value(not to be confused with
nil) or sentinel value, quite useful at times, in both Ruby and
Smalltalk.

Basically this gives you an object which is useful (only) because it
has a unique identity and is guaranteed not to appear by chance.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale