attr

T

Trans

In the upcoming release of Ruby Carats I have a little lib called
attr.rb.

What it does is define a mater #define_attribute which all attribute
defintions are routed thru. Then I redefine #attr (since current
definition is basically never used) to call #define_attribute that
takes multiple args. Here's an example:

.. attr :a, :a=

which is equivalent to:

.. attr_reader :a
.. attr_writer :a

It also has some extra freatures that are nice like:

.. attr :a?, :b!

which is the same as

.. def a?
.. @a ? true : @a
.. end
..
.. def b!(x)
.. @b.replace x
.. end

Also these return an array of the symbols of the methods that get
defined, so you can use public, private, protected on them. eg.

.. private attr :a

There are a couple of other features too, but I'll leave those aside
for now, as they are not important to this inquery.

So I have a few questions. First, what do you think of this in general?
Second, there is no "extra" convenient way to do an accessor b/c I
haven't been able to find a nice notation --one just has to put both,
'attr :a, :a='. Is this too inconvenient? Can anyone think of a good
notation?

Thanks,
T.
 
J

Jamis Buck

In the upcoming release of Ruby Carats I have a little lib called
attr.rb.

What it does is define a mater #define_attribute which all attribute
defintions are routed thru. Then I redefine #attr (since current
definition is basically never used) to call #define_attribute that

Well.... claiming that it is "basically never used" is dangerous. I've
used it, and I know I've seen code that uses it. Changing the
semantics of an existing method is always going to be dangerous, no
matter how infrequently you believe the method is used in practice.

Caution, caution, caution. :)
So I have a few questions. First, what do you think of this in general?
Second, there is no "extra" convenient way to do an accessor b/c I
haven't been able to find a nice notation --one just has to put both,
'attr :a, :a='. Is this too inconvenient? Can anyone think of a good
notation?

I like the features you've added, though. Could you perhaps call it
something other than "attr", to avoid breakage?

- Jamis
 
T

Trans

I like the features you've added, though.
Could you perhaps call it something other than
"attr", to avoid breakage?

I suppose, but first let me explain. It used to be called #def_attr for
the reason you state. But I always felt like I might as well use #attr
due to its _relative_ uselessness (i.e. overlap functionality with much
more commonly used methods). So I posted a topic here on this list
(110245) that asked about it, and the jist seemed to be that it was
pretty much abandoned. Also, keep in mind that programs using the old
#attr won't be effected unless they become a part of something that
requires this lib --and hell, the current definition of #attr almost
seems like a bug anyway; maybe poeple be happy to finally root them
out. Further, it is backward compatible with reader notation; just not
the accessor notation (i.e. 'attr :a, true').

Oh I forgot a question too. Sould 'attr :a=' create just a writer, like
I have it, or should it instead create a reader and a writer, since
writers are very uncommon? (Though in that case I don't know what
notation to use for just writer.)

-T.
 
R

Robert Klemme

Trans said:
In the upcoming release of Ruby Carats I have a little lib called
attr.rb.

What it does is define a mater #define_attribute which all attribute
defintions are routed thru. Then I redefine #attr (since current
definition is basically never used) to call #define_attribute that
takes multiple args. Here's an example:

. attr :a, :a=

which is equivalent to:

. attr_reader :a
. attr_writer :a

It also has some extra freatures that are nice like:

. attr :a?, :b!

which is the same as

. def a?
. @a ? true : @a
. end

Why not "def a?() @a end"?
. def b!(x)
. @b.replace x
. end

Hm, I don't like that because it's too special case. Also you might want
to be able to assign and to replace...
Also these return an array of the symbols of the methods that get
defined, so you can use public, private, protected on them. eg.

. private attr :a

There are a couple of other features too, but I'll leave those aside
for now, as they are not important to this inquery.

So I have a few questions. First, what do you think of this in general?
Second, there is no "extra" convenient way to do an accessor b/c I
haven't been able to find a nice notation --one just has to put both,
'attr :a, :a='. Is this too inconvenient? Can anyone think of a good
notation?

Although I find "attr_accessor" quite lengthy, I don't really see the
benefit of your proposal. And attr_accessor does indeed define reader and
writer for several attributes...

Kind regards

robert
 
T

Trans

. def a?
Why not "def a?() @a end"?

Becasue that would be the exact same as 'attr :a'. What would be the
point? This guaruntees only three possible return values: true, false,
and nil.
Hm, I don't like that because it's too special case.

Well, these _are_ special cases. Don't see any reason not to like them
b/c of that. Just dont use them. Since the "functional space" is simply
going unused anyway (i.e. symbols can end in ? and ! without quoting),
and it coorepsonds to certain forms of method definitions, I gave them
the most reasonble base-line usage I could think of.
Also you might want to be able to assign and to replace...

I think you'd just replace first from the calling routine, and then
assign. Or perhaps I misunderstand?
Although I find "attr_accessor" quite lengthy, I don't
really see the benefit of your proposal. And attr_accessor
does indeed define reader and writer for several attributes

Ah, but there are many advantages, not just the fact that attr is
shorter. You can define both readers and writers in the same call. The
names of the methods defined are returned so you can use public,
private, protected (and user defined methods too!) in front of them.
They also route through a common #define_attribute method, so there is
central control, and it stores all defined attribute methods so you can
ask for a list of them. It also has casting, somthing I came up with a
few years ago. Eg.
.. attr :a => :to_s

which defines

.. def a
.. @a.to_s
.. end

~T.
 
J

Jeffrey Moss

You know, this is commonly called "aspect oriented programming" if I am not
mistaken. You may want to look into it. I didn't find this paradigm very
easy to think in, but there are people out there who swear by it, so maybe
you should head in that direction and name the library accordingly.

I did a quick google search for aspect oriented programming ruby and found
some stuff out there that's already done. (http://aspectr.sf.net/)

-Jeff
 
G

Glenn Parker

Trans said:
So I have a few questions. First, what do you think of this in general?

Clever stuff for golfing, and possibly useful as a way to illustrate the
meta-programming flexibility of Ruby, but it adds nothing meaningful
while moderately obfuscating some simple tasks. You've come up with a
way to compress two or three lines of trivially understood Ruby down to
one line of obscure Ruby. To me, the original two or three "verbose"
lines are preferable because they are more easily recognized and
understood by a Ruby coder.
 
R

Robert Klemme

Trans said:
Becasue that would be the exact same as 'attr :a'. What would be the
point? This guaruntees only three possible return values: true, false,
and nil.

So you want to protect the real value. Is that the reasoning behind this?
Well, these _are_ special cases. Don't see any reason not to like them
b/c of that. Just dont use them. Since the "functional space" is simply
going unused anyway (i.e. symbols can end in ? and ! without quoting),
and it coorepsonds to certain forms of method definitions, I gave them
the most reasonble base-line usage I could think of.

Still you introduce a method in class Module that has some special behavior
which at least clutters namespace - even if unused. As Module is a very
basic class it's behavior should be most general, too - my 0.02 EUR. (You
can always define an add on that adds these methods.)
I think you'd just replace first from the calling routine, and then
assign. Or perhaps I misunderstand?

I meant that with only the replace version of the method there is no option
to assign to the member var. But with the getter you can already replace.
Of course, a.c! "foo" is shorter than a.c.replace "foo" - but then again,
it's a special case as it applies only to String (or at least mostly). :)
Ah, but there are many advantages, not just the fact that attr is
shorter. You can define both readers and writers in the same call.

I can do that with attr_accessor.
The
names of the methods defined are returned so you can use public,
private, protected (and user defined methods too!) in front of them.

This works only if the method returns a single symbol. Otherwise it's going
to be ugly:

class Module
def a(*x) :single end
def b(*x) [:a,:b] end
end

class Foo
def single; end
def a;end
def b;end

private a :a, :b
private b :c, :d # doesn't work
private *b :c, :d # doesn't work
private *b( :c, :d) # ugly
end
They also route through a common #define_attribute method, so there is
central control, and it stores all defined attribute methods so you can
ask for a list of them. It also has casting, somthing I came up with a
few years ago. Eg.
. attr :a => :to_s

which defines

. def a
. @a.to_s
. end

Interesting.

I'm sorry that I don't share your enthusiasm - I simply don't miss this
functionality.

Regards

robert
 
T

Trans

Robert said:
So you want to protect the real value. Is that the reasoning behind
this?

Not exactly. It is simply one readibility really and overlapping
functionality. For instance if you saw:

| case a?

What would you expect to be in the when clauses? It's customary to
expect a mthod ending in ? to return a "boolean" (true, false, nil).
You wouldn;t expect to see something like:

| a?.kind_of(Integer)

That's not to say you can't do it if you want, but is atypical. You
would just use 'a.kind_of(Integer)'.
Still you introduce a method in class Module that has some special behavior
which at least clutters namespace - even if unused. As Module is a very
basic class it's behavior should be most general, too - my 0.02 EUR.

I don;t see how it clutters namespace. It's one method. The special
behavior is quite basic, so I don't see how that's really get in the
way. But I guess that's my 2 cents too.
(You can always define an add on that adds these methods.)

Isn't that what I'm doing?
I meant that with only the replace version of the method there is no option
to assign to the member var. But with the getter you can already replace.
Of course, a.c! "foo" is shorter than a.c.replace "foo" - but then again,
it's a special case as it applies only to String (or at least
mostly). :)

Sure. I don't think the ! notaiton will be of great use. But niether is
the current definition of #attr. I just gave it something to do that's
simple and straigh foward that goes along with the gernal meaning of !
on the end of a method. But perhaps you have better use for the
notation?
I can do that with attr_accessor.

No becasue you get both a reader and a writer for each. What I mean is:

attr :a, :b=

Is one reader and one writer.
The
names of the methods defined are returned so you can use public,
private, protected (and user defined methods too!) in front of
them.

This works only if the method returns a single symbol. Otherwise it's going
to be ugly:

class Module
def a(*x) :single end
def b(*x) [:a,:b] end
end

class Foo
def single; end
def a;end
def b;end

private a :a, :b
private b :c, :d # doesn't work
private *b :c, :d # doesn't work
private *b( :c, :d) # ugly
end

Yes, that's something I have a distate for in Ruby --that there's no
way to pass through arguments-per-arguments via return. I.e.

| def self.b(*x) ; return *x ; end
| private b

#b still returns an array with or without the * in 'return *x', it
seems. But there is of course the solution of altering public, private
and protected to accept an array.
Interesting.

I'm sorry that I don't share your enthusiasm - I simply don't miss this
functionality.

Why would you miss it? You have never had it :) I have been using for
awhile now. Most of the time it's of small consequence. But every once
in a while these extra "touches" come in quite handy.

T.
 
T

Trans

Thanks Glenn,

But do you really find something like:

| attr :a, :a=, :c?

so obfuscating? Every thing has some learning curve to it. I grant you.
But my bet is that this notation would be almost completely undestood
on one's first hunch.

T.
 
T

Trans

Hi Jeffery,

I wouldn't exaclty call it AOP, although I can understand some analogy
here.

If you'd like to see some extensive work on the subject of Ruby and AOP
have a look at the RcrFoundy on the Ruby Garden Wiki. It's also a
common topic at on the suby-ruby mailing list.

Thanks,
-T.
 
C

Csaba Henk

Becasue that would be the exact same as 'attr :a'. What would be the
point? This guaruntees only three possible return values: true, false,
and nil.

That's right, but what's the use of such a method? Could you show me a
situation when one would intend to restrict a query to have only
true/false/nil as a result? Upon testing, true and the (not nil, false)
object nil, object itself does to same, so what's the point then?

Csaba
 
G

Glenn Parker

Trans said:
Thanks Glenn,

But do you really find something like:

| attr :a, :a=, :c?

so obfuscating? Every thing has some learning curve to it. I grant you.
But my bet is that this notation would be almost completely undestood
on one's first hunch.

I would probably guess correctly about ":a=", but not ":c?".

I would view these things differently if they were incorporated into the
language standard, but as add-ons they just confuse things for little
perceivable benefit. I mean, "attr_accessor :symbol" is not transparent
to me either, but it's part of the accepted programming conventions for
Ruby, and I use it because it requires nothing beyhond baseline Ruby
knowledge for the reader. When you want to push beyond that baseline,
you should aim to get more bang for your buck.
 
F

Florian Gross

Trans said:
In the upcoming release of Ruby Carats I have a little lib called
attr.rb.

. attr :a, :a=
. attr :a?, :b!

Quite nifty, all that. I don't quite understand the people who think it
is obscure or who think it clutters the built-in methods.

This is a nice extension. While I would not use attr :a, :a= over
attr_accessor :a (the latter has already become a convention) I could
see myself using this because of the attr :a?, :a= and attr :x =>
:to_s functionality.

What I don't quite understand is why you're not remaining compatible
with the original attr(). After all you would just have to check if you
have two arguments of which the second is either false or true. (While
this would still be slightly incompatible in the attr :foo, "I like to
use Strings for true" case I'm pretty sure you can safely ignore it.
Maybe a note ought to go into the documentation, but I can't see this
causing trouble.)

Oh, and I think that the :x! feature is quite useless. This is an
extremely rare special case and I think it's more obvious if written
out. Or did you find lots of use cases for it?

Perhaps you could also allow it to take a block that would be
instance_eval()uated in the method at the beginning. That could be used
for introducing checks, converting values and so on. It would not
provide much above writing the method out, but it could still make sense.
 
R

Robert Klemme

Trans said:
this?

Not exactly. It is simply one readibility really and overlapping
functionality. For instance if you saw:

| case a?

What would you expect to be in the when clauses? It's customary to
expect a mthod ending in ? to return a "boolean" (true, false, nil).
You wouldn;t expect to see something like:

| a?.kind_of(Integer)

Not exactly. But since Ruby can treat any object properly in a boolean
context, why waste some processing cycles on conversion if not because of
information hiding (i.e. prevent leakage of a member value)?
That's not to say you can't do it if you want, but is atypical. You
would just use 'a.kind_of(Integer)'.

Or rather "Integer === a". :)
I don;t see how it clutters namespace. It's one method. The special
behavior is quite basic, so I don't see how that's really get in the
way. But I guess that's my 2 cents too.

Now we got 0.04 already. :)
Isn't that what I'm doing?

I thought you were proposing to exchange the default behavior.
mostly). :)

Sure. I don't think the ! notaiton will be of great use. But niether is
the current definition of #attr. I just gave it something to do that's
simple and straigh foward that goes along with the gernal meaning of !
on the end of a method. But perhaps you have better use for the
notation?


No becasue you get both a reader and a writer for each. What I mean is:

attr :a, :b=

Ah, ok I see. Thx for clarifying.
Is one reader and one writer.
The
names of the methods defined are returned so you can use public,
private, protected (and user defined methods too!) in front of
them.

This works only if the method returns a single symbol. Otherwise it's going
to be ugly:

class Module
def a(*x) :single end
def b(*x) [:a,:b] end
end

class Foo
def single; end
def a;end
def b;end

private a :a, :b
private b :c, :d # doesn't work
private *b :c, :d # doesn't work
private *b( :c, :d) # ugly
end

Yes, that's something I have a distate for in Ruby --that there's no
way to pass through arguments-per-arguments via return. I.e.

| def self.b(*x) ; return *x ; end
| private b

#b still returns an array with or without the * in 'return *x', it
seems. But there is of course the solution of altering public, private
and protected to accept an array.
Hm....
Interesting.

I'm sorry that I don't share your enthusiasm - I simply don't miss this
functionality.

Why would you miss it? You have never had it :) I have been using for
awhile now. Most of the time it's of small consequence. But every once
in a while these extra "touches" come in quite handy.

But you didn't have it either and apparently you missed it, didn't you?
;-)

Regards

robert
 
Z

Zev Blut

Well.... claiming that it is "basically never used" is dangerous. I've
used it, and I know I've seen code that uses it. Changing the
semantics of an existing method is always going to be dangerous, no
matter how infrequently you believe the method is used in practice.

Caution, caution, caution. :)

I fully agree, unless you have access to all the source code ever
written in Ruby it is pretty hard to say that is never used. Of
course, it is very easy to say something such as "I never use it".
But, then how do we know if other people are using certain methods and
syntax? I was pretty shocked to see lots of usage of the for statement
in some of the source code included in the standard Ruby libraries.
Why would anyone use for when the each method exists, especially those
who have committed to the Ruby base? Ignore that last question it is
only to highlight how I thought most Ruby experts would not use the
for statement.

Assuming we have access to lots of source we could run a few
searches of various method/syntax usage and tally up the results.
Luckily, Satoru Takabayashi, is writing a nice tool called "gonzui" to
help speed up searching your source. I installed it this weekend and
did a bit of playing around with it. Though it is a bit rough around
the edges, it shows a lot of potential and is pretty useful now.
Certainly faster than grep once you build the indexes.

Check it out:
http://namazu.org/~satoru/gonzui/

Cheers,
Zev
 
D

David A. Black

Hi --

I suppose, but first let me explain. It used to be called #def_attr for
the reason you state. But I always felt like I might as well use #attr
due to its _relative_ uselessness (i.e. overlap functionality with much
more commonly used methods). So I posted a topic here on this list
(110245) that asked about it, and the jist seemed to be that it was
pretty much abandoned. Also, keep in mind that programs using the old
#attr won't be effected unless they become a part of something that
requires this lib --and hell, the current definition of #attr almost
seems like a bug anyway; maybe poeple be happy to finally root them
out. Further, it is backward compatible with reader notation; just not
the accessor notation (i.e. 'attr :a, true').


laptop:/usr/local/lib/ruby/1.8$ ruby -ne 'print $_ if /^\s+attr\s/'
`find . -name "*.rb"` | wc
76 217 1902

I think some of the ideas you're suggesting might have some interest
but I definitely wouldn't include a module that redefined attr in an
incompatible way.


David
 
T

Trans

Could you rerun with /^\s+attr\s+\:/' since attr can be used for other
things too?

Nonetheless that's still pretty low and and I suspect that many
occurances are also only a matter of example --not even real use. But
I realize it does get used occasionally. I'm simply wonder if it is
enough at this point to warrant continued support? Is there some
complelling reason to use it rather than the vastly more common attr_*
methods? I don't see any reason to do so. It's a nice short method name
and it would nice if it were actually more useful, rather then just an
obsure and rarely used anomally.

Anyway I am willing to change the name (any suggestions?) or at least
make it backward compatible (any reasons not to do that?)

BTW I wonder about how #attr works. Hal wrote in his book that #attr
creates the @var and the method(s) #var/#var=. How does it "create" the
instance var? Doesn't it actually just create the methods and the
instance var gets created via their use?

T.
 
T

Trans

Thanks for the support Florian.
What I don't quite understand is why you're not
remaining compatible with the original attr().

An excellent point! All things being equal, I will do exactly that.
Thanks!
Oh, and I think that the :x! feature is quite useless. This is
an extremely rare special case and I think it's more obvious
if written out. Or did you find lots of use cases for it?

No. The only thing that comes to mind is in combination with a casting.
Somthing like:

| attr :a! => :upcase

which creates

| def a!(x)
| @a.replace(x.upcase)
| end

Better, but still doesn't seem all that useful really --as has been
pointed out. I've though about using the ! to build a reader and
writer, but that doesn't fit the profile. ! has a general meaning of
effecting the object in a special internal way.

There is also another form which I thought might be nice to have, a
getter/setter: If an argument is given it acts as a setter, if not it
acts as a getter. But I have no simple notion to use for it. At the
moment it can be done like this:

| attr :"a()"

But I'm not too sure about it.
Perhaps you could also allow it to take a block that would
be instance_eval()uated in the method at the beginning.

I've thought about that. In fact I think I had that in there at one
point. But like you say it seemed like you'd might as well be writting
the method out at that point. But maybe there's merit to it for other
reasons --sometimes I wish def itself took a block form, eg.
| def a { #... }

T.
 
D

David A. Black

Hi --

No. The only thing that comes to mind is in combination with a casting.
Somthing like:

| attr :a! => :upcase

which creates

| def a!(x)
| @a.replace(x.upcase)
| end

But think of that from the point of view of someone using the class,
and writing code in a different file. What you'd see is just this
(using 'text' as the accessor):

require 'some_file'

obj = A.new
obj.text = "Hi there."
obj.text!
puts obj.text # "HI THERE."

which is awfully obscure. In essence, there's a verb missing; it's
like doing:

some_string!

instead of

some_string.upcase!

Also, !-methods don't have any special correspondence to the 'replace'
operation. All the ! means is that the operation is dangerous (I
think that's the adjective Matz has used) -- which often means it
changes the receiver, but doesn't have to, and it could be a change
that isn't a replace operation.


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top