Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Sweetest Accessor?

Reply
Thread Tools

Sweetest Accessor?

 
 
Xiong Changnian
Guest
Posts: n/a
 
      03-27-2007
I'm learning, so I'm trying different idioms. Perhaps in the end it
doesn't matter but I've been working on particularly terse idioms.

One particular demand is for object data accessor methods. There are a
lot of them and they all look somewhat alike -- sounds like a demand for
laziness. What's the shortest, "sweetest" accessor sub?

Here's what I've got (eg):

METHOD1:

sub name {
my $obj = shift;
$obj->{NAME} = shift ||
$obj->{NAME};
};

This allows both gets and puts:

$oldname = $obj->name;
$obj->name ($newname);

It still doesn't satisfy me. The needless assignment-to-self irks. Note
that it does no good to change the order of precedence so that
$obj->{NAME} is returned (without assigning it) if shift tests false; by
then it's too late and shift has clobbered the old value. So here I test
shift within the right-hand side expression before making the
assignment.

Here's another:

METHOD2:

sub name {
$_[1] ? $_[0]->{NAME} =
$_[1] : $_[0]->{NAME};
};

This avoids the needless assignment but now there's a second get of
$_[1]. Supposing that the object is more complex and that hitting the
object is more expensive than hitting the param, I'd guess this second
version is more efficient. Also, no assignment to a temp $obj. It looks
a bit odd to line break the statement after the assignment operator.

I realize that some oppose needlessly terse or obscure code but I'll ask
for forgiveness here. After all, an accessor method is simple. In the
end, it's a wash anyway; I'm just experimenting. I'll take comments on
either method shown and I'd love to see suggestions.
--
Xiong Changnian
xiong102ATxuefangDOTcom

--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
 
 
 
anno4000@radom.zrz.tu-berlin.de
Guest
Posts: n/a
 
      03-27-2007
Xiong Changnian <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> I'm learning, so I'm trying different idioms. Perhaps in the end it
> doesn't matter but I've been working on particularly terse idioms.
>
> One particular demand is for object data accessor methods. There are a
> lot of them and they all look somewhat alike -- sounds like a demand for
> laziness. What's the shortest, "sweetest" accessor sub?
>
> Here's what I've got (eg):
>
> METHOD1:
>
> sub name {
> my $obj = shift;
> $obj->{NAME} = shift ||
> $obj->{NAME};
> };
>
> This allows both gets and puts:
>
> $oldname = $obj->name;
> $obj->name ($newname);
>
> It still doesn't satisfy me. The needless assignment-to-self irks. Note
> that it does no good to change the order of precedence so that
> $obj->{NAME} is returned (without assigning it) if shift tests false; by
> then it's too late and shift has clobbered the old value. So here I test
> shift within the right-hand side expression before making the
> assignment.
>
> Here's another:
>
> METHOD2:
>
> sub name {
> $_[1] ? $_[0]->{NAME} =
> $_[1] : $_[0]->{NAME};
> };
>
> This avoids the needless assignment but now there's a second get of
> $_[1]. Supposing that the object is more complex and that hitting the
> object is more expensive than hitting the param, I'd guess this second
> version is more efficient. Also, no assignment to a temp $obj. It looks
> a bit odd to line break the statement after the assignment operator.
>
> I realize that some oppose needlessly terse or obscure code but I'll ask
> for forgiveness here. After all, an accessor method is simple. In the
> end, it's a wash anyway; I'm just experimenting. I'll take comments on
> either method shown and I'd love to see suggestions.


You have noticed one problem with your accessors (multiple assignment).
Another problem is that you won't be able to assign a boolean false
value that way.

The standard get-set accessor in Perl is

sub name {
my $obj = shift;
$obj->{ name} = shift if @_;
$obj->{ name};
}

It hinges on the presence of two arguments, not on the value of the
second argument, so you can assign boolean false values, (including
undef).

For low-level read-write access I am partial to lvalue accessors
these days:

sub name : lvalue { shift()->{ name} }

These are (usually) not for the class user (because you can't check
lvalues), but for your own use when you write the class code. Give
them an initial "_" if you want to make that clear.

Anno
 
Reply With Quote
 
 
 
 
Mumia W.
Guest
Posts: n/a
 
      03-27-2007
On 03/27/2007 08:08 AM, Xiong Changnian wrote:
> I'm learning, so I'm trying different idioms. Perhaps in the end it
> doesn't matter but I've been working on particularly terse idioms.
> [...]


perldoc perltoot
perldoc Class::Struct
perldoc Class::Accessor


 
Reply With Quote
 
Xiong Changnian
Guest
Posts: n/a
 
      03-28-2007
In article <(E-Mail Removed)>,
http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de wrote:

> Another problem is that you won't be able to assign a boolean false
> value that way.


Well, I'm not sure that's a problem. I abhor boolean false values as a
matter of taste. Reserving FALSE demands that every value assigned to a
variable have a TRUE value (obviously) and I think that's good style. I
realize that someone else will be quite comfortable with, say, integer
zero values in some places and require an accessor that permits them. I
just don't.

If I ever thought I would want deliberately to set a variable inside a
complex data structure to 0, "", or undef, I'd write a distinct "clear"
method.


> The standard get-set accessor in Perl is
>
> sub name {
> my $obj = shift;
> $obj->{ name} = shift if @_;
> $obj->{ name};
> }


No offense, but that's neither short nor sweet. I particularly don't
care for mixing shift and @_ in the same sub -- visually.

Of course, a working accessor might be written in any number of ways and
perhaps there are several idioms that will all compile to equivalent
byte code or be equally efficient. My immediate goal here is terseness,
sweetness -- "niftyness", if you will. Sorry if that sounds trivial.


> sub name : lvalue { shift()->{ name} }


I really, really like the idea of lvalue subs. They make calling syntax
much more symmetrical and "natural". I was scared off by dire warnings
(eg):

"WARNING: Lvalue subroutines are still experimental and the
implementation may change in future versions of Perl."

I'd welcome comments. Are lvalue subs coming or going? Will my code blow
up next release?

I would like to see what sort of Frankenstein's Monsters I can build
with lvalue subs, prototypes, and overloading. I'm sure any code I post
from that lab will raise eyebrows.


In article <ddaOh.131662$(E-Mail Removed) ink.net>,
"Mumia W." <(E-Mail Removed)> wrote:

> perldoc Class::Accessor


I'm sure you mean well but you must be a get-the-job-done type. It's
useless to me to let George do it; I'm experimenting.

FWIW, here's what the indicated module's doc says it generates:

# Your foo may vary.
sub foo {
my($self) = shift;
if(@_) { # set
return $self->set('foo', @_);
}
else {
return $self->get('foo');
}
}

That is definitely not a terse idiom.

I dunno, but maybe my METHOD2 is as far as one can go in my chosen
direction:

METHOD2:

sub name {
$_[1] ? $_[0]->{NAME} =
$_[1] : $_[0]->{NAME};
};

Still, nothing can beat the lvalue sub for sheer terse beauty. If only
we could depend on it?
--
Xiong Changnian
xiong102ATxuefangDOTcom

--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
anno4000@radom.zrz.tu-berlin.de
Guest
Posts: n/a
 
      03-28-2007
Xiong Changnian <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> In article <(E-Mail Removed)>,
> (E-Mail Removed)-berlin.de wrote:
>
> > Another problem is that you won't be able to assign a boolean false
> > value that way.

>
> Well, I'm not sure that's a problem. I abhor boolean false values as a
> matter of taste. Reserving FALSE demands that every value assigned to a
> variable have a TRUE value (obviously) and I think that's good style. I
> realize that someone else will be quite comfortable with, say, integer
> zero values in some places and require an accessor that permits them. I
> just don't.
>
> If I ever thought I would want deliberately to set a variable inside a
> complex data structure to 0, "", or undef, I'd write a distinct "clear"
> method.


I don't think you'll be happy with that in the long run. Many fields
take values that happen to be false in the normal course of things.
Suppose you have a field "score" you want to count up and down:

if ( $won ) {
$player->score( $player->score + 1);
} else {
$player->score( $player->score - 1);
}

That would fail to change the score if the score would have reached
zero. You'd need an ugly workaround, even if you have a special method
"->clear_score" to set it to zero.

> > The standard get-set accessor in Perl is
> >
> > sub name {
> > my $obj = shift;
> > $obj->{ name} = shift if @_;
> > $obj->{ name};
> > }

>
> No offense, but that's neither short nor sweet.


I'm not claiming short and sweet. It's standard.

> I particularly don't
> care for mixing shift and @_ in the same sub -- visually.


Why?

> Of course, a working accessor might be written in any number of ways and
> perhaps there are several idioms that will all compile to equivalent
> byte code or be equally efficient. My immediate goal here is terseness,
> sweetness -- "niftyness", if you will. Sorry if that sounds trivial.
>
>
> > sub name : lvalue { shift()->{ name} }

>
> I really, really like the idea of lvalue subs. They make calling syntax
> much more symmetrical and "natural". I was scared off by dire warnings
> (eg):
>
> "WARNING: Lvalue subroutines are still experimental and the
> implementation may change in future versions of Perl."


I'm not much worried by that. There seems to be little ongoing
discussion of lvalue subs. I think they are here to stay.

Anno
 
Reply With Quote
 
Xiong Changnian
Guest
Posts: n/a
 
      03-28-2007
In article <(E-Mail Removed)>,
(E-Mail Removed)-berlin.de wrote:

> Many fields
> take values that happen to be false...


Well, yes; depends on your application. The stuff I'm doing now, this
doesn't usually come up. I make it *not* come up.

Please remember this is all a learning project for me; I'm going in
directions that have nothing to do with getting-the-job-done. With my
background, Perl is a novel and exciting language with amazingly
succinct ways of doing things. I'm pushing the edges of that as far as
possible.

Just to put a little contrast on that, I'm also designing, for the
benefit of some of my students, a set of relay logic gates; I've got up
to the full adder. This has been done before, of course, but perhaps not
with my particular design restrictions: all lines high or low, nothing
open or float; all coils grounded at one end. The intent is to make the
circuits 74CXX compatible and the most fundamental operations of a
binary digital computer as transparent as possible to the student
without sacrificing rigor. Obviously, I could get-the-job-done a lot
more easily.

Sorry if I seem to be banging my head deliberately against the wall.


Xiong wrote:

> > I particularly don't
> > care for mixing shift and @_ in the same sub -- visually.

>
> Why?


I'd like to respond to your question but I'm not sure how; it's just a
stylistic or gut feeling. For complex subs, I like the idiom of shifting
all the params into my variables; it puts a nice little self-documenting
declaration block up top. Now that I've been fooling around awhile, I'm
starting to see the limitations and inefficiencies in this and I'm
trying things the other way. One bone I have to pick with @_ is that it
allows me to clobber the actual param, which I generally don't want to
do. Also, after a lifetime of subscripting, I'm straining now to avoid
it. On the other hand, there are elegant @_ and $_[$n] approaches.

If it makes me look like a more reasonable person, my generic new shifts
for the class, then passes @_ to init.


> > "WARNING: Lvalue subroutines are still experimental and the
> > implementation may change in future versions of Perl."

>
> I'm not much worried by that. There seems to be little ongoing
> discussion of lvalue subs. I think they are here to stay.


Well, I *really* appreciate that assurance. I'm going to take your
comment as a license to go hog wild. The lvalue accessor you posted may
well be the shortest distance between two points -- and looks good in
the calling context. Throw in prototypes and a little overloading and I
can imagine writing some lucid code in the caller. Now, if I could only
figure out how to get rid of those superfluous commas....

Of course, it's all fake and heaven help the intrepid who use my modules
without reading the docs. But then, I don't expect my stuff to be on
CPAN any time soon.

Thanks again.
--
Xiong Changnian
xiong102ATxuefangDOTcom

--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
anno4000@radom.zrz.tu-berlin.de
Guest
Posts: n/a
 
      03-28-2007
Xiong Changnian <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> In article <(E-Mail Removed)>,
> (E-Mail Removed)-berlin.de wrote:
>
> > Many fields
> > take values that happen to be false...

>
> Well, yes; depends on your application. The stuff I'm doing now, this
> doesn't usually come up. I make it *not* come up.


Well, your question came around as being about the style of general-
purpose accessors. I would not recommend a general-purpose accessor
that doesn't transfer certain values.

[snip]

> > > I particularly don't
> > > care for mixing shift and @_ in the same sub -- visually.

> >
> > Why?

>
> I'd like to respond to your question but I'm not sure how; it's just a
> stylistic or gut feeling. For complex subs, I like the idiom of shifting
> all the params into my variables; it puts a nice little self-documenting
> declaration block up top.


That isn't tied to shifting. The most self-documenting way of
parameter assignment would have to be:

my ( $name, $age, $occupation) = @_;

Shifting parameters off @_ is done for various reasons:

- You want to deal with each parameter individually before you
enter the body of the sub

my $name = shift || 'anonymous';
my $age= shift || 0;
my $occupation = $default_occupation[ $age];

- You want to get things out of the way and deal with the
remaining arguments uniformly

my $mode = shift;
for ( @_ ) { # ...

- In method calls, you shift off the invocant (class or object)
to make the content of @_ conform to the parameters given at
the call site;

$obj->meth( $name, $age, $occupation);

# corresponds to

my $obj = shift;
my ( $name, $age, $occupation) = @_;

> Now that I've been fooling around awhile, I'm
> starting to see the limitations and inefficiencies in this and I'm
> trying things the other way. One bone I have to pick with @_ is that it
> allows me to clobber the actual param, which I generally don't want to
> do. Also, after a lifetime of subscripting, I'm straining now to avoid
> it. On the other hand, there are elegant @_ and $_[$n] approaches.


These are usually restricted to small (one-line) subs. If anything
substantial goes on in the sub body, assignment of parameters to
named variables is the norm. Unless you *want* to change an argument,
or do other things that don't work on a copy.

BTW, shift() as such doesn't stop you from changing a parameter.
"

> If it makes me look like a more reasonable person, my generic new shifts
> for the class, then passes @_ to init.


Right, that's one of the cases I mentioned. And congratulations for
providing a separate initializer. It's all too often forgotten.

[snip lvalue, except]

> the calling context. Throw in prototypes and a little overloading and I
> can imagine writing some lucid code in the caller. Now, if I could only


You can't throw prototypes into an OO design. Prototypes are ignored
in method calls. In general, prototypes appear to introduce more
problems than they solve. It is true that they let you (sometimes)
design a particularly intuitive interface. Restrict prototypes to
such cases, don't use them as a matter of course.

Overloading goes a much longer way in the direction of intuitive
interfaces, but is also not without problems. In a general-purpose
class the user should be able to opt out of overloading.

Anno
 
Reply With Quote
 
Xiong Changnian
Guest
Posts: n/a
 
      03-29-2007
In article <(E-Mail Removed)>,
(E-Mail Removed)-berlin.de wrote:

> BTW, shift() as such doesn't stop you from changing a parameter.


That statement baffles me. Perhaps I'm missing something. Here's my
understanding -- not to lecture, but please tell me where I run off the
bridge.

All in all -- as I've thanked this poster before -- I like the lvalue
sub syntax if I'm going to set an actual param value. I've been
sidestepping this issue for the most part because I'm writing object
methods, which are *expected* to take an object (hash ref) as a param
and tinker with the referent.

* * *

@_ contains aliases to actual params -- the "stuff" supplied as params
by the calling context. Thus, in:

$, = " "; $\ = "\n";
$foo = 'goodstuff';
$bar = 'morestuff';
$error = dosomething($foo, $bar);
print $foo, $bar;

SUB1:
sub dosomething {
$_[0] = 'bang';
print $_[0], $_[1];
return 0;
};

The literal 'bang' clobbers the calling context's value ('goodstuff') of
$foo -- bug, feature, or sloppy coder, you decide. In essence, it's a
call-by-reference but no dereffing is expected. Output reads:

bang morestuff
bang morestuff

.... $bar is untouched.

However:

SUB2:
sub dosomething {
my $stuff = shift;
$stuff = 'bang';
print $_[0], $_[1], '\n';
return 0;
};

Now nothing is clobbered; output reads:

morestuff
goodstuff morestuff

.... because shift -- implicitly, shift(@_) -- takes on the value of
$_[0] and then makes $_[0] an alias to $bar, so:

SUB3:
sub dosomething {
my $stuff = shift;
$_[0] = 'bang';
print $_[0], $_[1], '\n';
return 0;
};

gives output:

bang
goodstuff bang

The assignment inside the sub now clobbers $bar but $foo is untouched.

This will clobber neither $foo nor $bar:

SUB4:
sub dosomething {
my $stuff = shift;
$_[1] = 'bang';
print $_[0], $_[1];
return 0;
};

Output:

morestuff bang
goodstuff morestuff

Explanation being that at the time of shift-ing, $_[1] became undef --
and stayed that way until defined by literal assignment; the alias to
$bar is lost.

BTW:

SUB5:
sub dosomething {
@_ = ('bang', 'whimper');
print $_[0], $_[1];
return 0;
};

Output:

bang whimper
goodstuff morestuff

Assigning to @_ itself, as opposed to a subscripted element, does *not*
clobber the actual params. It has to be the whole bananna:

SUB6:
sub dosomething {
@_[0,1] = ('bang', 'whimper');
print $_[0], $_[1];
return 0;
};

Output:

bang whimper
bang whimper

Array slice isn't good enough.

* * *

I read an argument against using @_ even in the case of throwaway actual
params; you don't care if they get clobbered. What if your caller
doesn't read docs?

Calling SUB1 with:

$error = dosomething('nixon', 'agnew');

raises a fatal exception because attempting to assign to $_[0] is an
attempt to assign to a literal. Calling SUB2 is fine. FWIW, even SUB4
works okay; 'nixon' is shifted off and 'agnew' ducks the bullet.

Naturally, this is no barrier to using @_ but it's a caution. ("Do I
know what I'm doing? Okay then.")

* * *

So, it's my understanding that if I consistently shift off all my
params, I *can't* clobber them. If I use $_[$n] then it's up to me
either to keep it on the right side or deliberately clobber. If I mix
shift and $_[$n] then I'd better *really* be careful because whether I
want to clobber or not, I won't get what I want unless either I get
lucky or pay close attention to what I'm doing.

Of course, I can always shift all params and then proceed to assign
freely to $_[$n] -- but then I'm just using it as a scratch variable.

I suppose I can always test something, maybe assign a default to $_[$n],
then later shift something off. But tell me honestly: If you knew I'd
done that without good and sufficient reason, would you rush to switch
off the machine when I got my fingers caught in the gears?
--
Xiong Changnian
xiong102ATxuefangDOTcom

--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      03-29-2007
Xiong Changnian wrote:
> In article <(E-Mail Removed)>,
> (E-Mail Removed)-berlin.de wrote:
>
>> BTW, shift() as such doesn't stop you from changing a parameter.

>
> That statement baffles me. Perhaps I'm missing something. Here's my
> understanding -- not to lecture, but please tell me where I run off the
> bridge.
>
> All in all -- as I've thanked this poster before -- I like the lvalue
> sub syntax if I'm going to set an actual param value. I've been
> sidestepping this issue for the most part because I'm writing object
> methods, which are *expected* to take an object (hash ref) as a param
> and tinker with the referent.
>
> * * *
>
> @_ contains aliases to actual params -- the "stuff" supplied as params
> by the calling context. Thus, in:
>
> $, = " "; $\ = "\n";
> $foo = 'goodstuff';
> $bar = 'morestuff';
> $error = dosomething($foo, $bar);
> print $foo, $bar;


[ snip ]

> However:
>
> SUB2:
> sub dosomething {
> my $stuff = shift;
> $stuff = 'bang';
> print $_[0], $_[1], '\n';
> return 0;
> };
>
> Now nothing is clobbered; output reads:
>
> morestuff
> goodstuff morestuff


No, the output *should* read:

morestuff \n
goodstuff morestuff


> ... because shift -- implicitly, shift(@_) -- takes on the value of
> $_[0] and then makes $_[0] an alias to $bar, so:
>
> SUB3:
> sub dosomething {
> my $stuff = shift;
> $_[0] = 'bang';
> print $_[0], $_[1], '\n';
> return 0;
> };
>
> gives output:
>
> bang
> goodstuff bang


It *should* look more like:

bang \n
goodstuff bang


I take it you didn't test this stuff?



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
Dr.Ruud
Guest
Posts: n/a
 
      03-29-2007
Xiong Changnian schreef:

> The literal 'bang' clobbers the calling context's value ('goodstuff')
> of $foo -- bug, feature, or sloppy coder, you decide. In essence,
> it's a call-by-reference but no dereffing is expected.


You should stop making such statements until you understand why it is
like it is.
But even if you don't, I won't notice it, goodbye.

--
Affijn, Ruud

"Gewoon is een tijger."

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
what's the sweetest crappy camera you had? Mike Henley Digital Photography 25 05-25-2004 04:40 AM



Advertisments