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?

···

--
Posted via http://www.ruby-forum.com/.

no, we don't. I'd argue strongly against "so many". It is highly non-idiomatic.

···

On Jun 25, 2009, at 11:05 , Marc Heiler 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'

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 Thu, Jun 25, 2009 at 2:05 PM, Marc Heiler<shevegen@linuxmail.org> wrote:

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'

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 Doe"
      phone "206-867-5309"
    end

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

~ j.

···

On Thu, Jun 25, 2009 at 11:29 AM, Ryan Davis<ryand-ruby@zenspider.com> wrote:

On Jun 25, 2009, at 11:05 , Marc Heiler 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.

This is the pattern I use:

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 Brown <gregory.t.brown@gmail.com>

On Thu, Jun 25, 2009 at 2:05 PM, Marc Heiler<shevegen@linuxmail.org> > wrote:
> 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'

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

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.

···

--
Posted via http://www.ruby-forum.com/\.

Really? Can you give me an example?

···

On Fri, Jun 26, 2009 at 4:00 AM, Fabian Streitel<karottenreibe@googlemail.com> wrote:

This is the pattern I use:

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:

Hi --

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 Fri, 26 Jun 2009, Marc Heiler wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

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

···

On Jun 25, 2009, at 12:37 , Marc Heiler 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.

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 Brown <gregory.t.brown@gmail.com>

On Fri, Jun 26, 2009 at 4:00 AM, Fabian > Streitel<karottenreibe@googlemail.com> wrote:
>> This is the pattern I use:
>>
>> 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

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]

···

On Sat, Jun 27, 2009 at 10:42 AM, Fabian Streitel<karottenreibe@googlemail.com> wrote:

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

Gregory Brown 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

Fabian Streitel 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.

···

--
Posted via http://www.ruby-forum.com/\.

> 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 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 4:52 PM, Fabian Streitel<karottenreibe@googlemail.com> wrote:

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

···

On Jun 27, 11:26 pm, Daniel DeLorme <dan...@dan42.com> wrote:

Gregory Brown 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

Ooh, neat trick. Thanks for sharing.

-greg

···

On Sat, Jun 27, 2009 at 11:26 PM, Daniel DeLorme<dan-ml@dan42.com> wrote:

Gregory Brown 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

Ok, I guess you have to be trying, but I can still break this:

class Everything
  def == other
    true
  end
end

name Everything.new

And the way to fix it:

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

Out of sheer curiosity, I did benchmark this, and the Nothing method is
slightly faster. Probably worth it if anyone wants to put this in a library --
otherwise, I'll go with the more readable (to me):

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

···

On Saturday 27 June 2009 10:26:51 pm Daniel DeLorme wrote:

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

Gregory Brown 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<karottenreibe@googlemail.com> wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

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...