Implicit iterator variable $_ changing to ### upon variable assignment?

D

Derek Basch

Hello all,

I have ran into a very confusing problem and I hoped someone could help
me. This function is supposed to return a hash of the accessors and
their associated values for a given class.


------------------------------------------
package Test;

sub accessors_values {
my $self = shift;
my %accessors_values;

foreach $_ ($self->accessors()) {
print "$_\n";
my $value = $self->_accessor_class($_)->get($_);
print "$_ : $value\n";
}
return %accessors_values;
}

.........

------------------------------------------

Gives this output:
------------------------------------------
password
### : carefree
user_id
### : 323227
first_login
### : 2006.08.08.12.47.13
last_login
### : 2006.08.08.12.47.13
------------------------------------------

Where the heck is the '###' coming from? How is assigning a value to
the $value variable causing the implicit iterator variable $_ to become
'###' ?

The functions that the code calls are large so I will give a synopsis
of what they return:

$self->accessors returns an array of accessor names
$self->_accessor_class returns a hash ref to a class
$self->get returns a scalar value

Any help is greatly appreciated.

Thanks,
Derek Basch
 
D

Derek Basch

Derek said:
Hello all,

I have ran into a very confusing problem and I hoped someone could help
me. This function is supposed to return a hash of the accessors and
their associated values for a given class.


------------------------------------------
package Test;

sub accessors_values {
my $self = shift;
my %accessors_values;

foreach $_ ($self->accessors()) {
print "$_\n";
my $value = $self->_accessor_class($_)->get($_);
print "$_ : $value\n";
}
return %accessors_values;
}

........

------------------------------------------

Gives this output:
------------------------------------------
password
### : carefree
user_id
### : 323227
first_login
### : 2006.08.08.12.47.13
last_login
### : 2006.08.08.12.47.13
------------------------------------------

Where the heck is the '###' coming from? How is assigning a value to
the $value variable causing the implicit iterator variable $_ to become
'###' ?

The functions that the code calls are large so I will give a synopsis
of what they return:

$self->accessors returns an array of accessor names
$self->_accessor_class returns a hash ref to a class
$self->get returns a scalar value

Any help is greatly appreciated.

Thanks,
Derek Basch

I answered my own question. The implicit iterator was apparently being
set to "##" by one of the functions that I called from within the sub.
I didn't realize that it could be affected in such a way. Live and
learn I guess.

Thanks Anyways,
Derek Basch
 
D

Derek Basch

Derek said:
I answered my own question. The implicit iterator was apparently being
set to "##" by one of the functions that I called from within the sub.
I didn't realize that it could be affected in such a way. Live and
learn I guess.

Thanks Anyways,
Derek Basch

Note that the way I found this error was by trying to do this:

%accessors_values = map { $iter =>
$self->_accessor_class($iter)->get($iter) } $self->accessors();

The foreach above was my attempt to break the problem into smaller
units for testing.
So, you can solve this problem by not using the implicit iterator with
a foreach loop.

What I didn't mention was that the get function above uses a "while
<FILEHANDLE>"
loop. The "while <FILEHANDLE>" loop uses an implicit iterator and the
map function also uses an implicit iterator.

So, if you use map with an EXPR that uses the "while <FILEHANDLE>"
idiom the map implicit iterator value will be replaced with the "while
<FILEHANDLE>" implicit iterator value. You must use foreach instead of
map.

I hope that helps someone in the future :)

Derek Basch
 
D

Derek Basch

Michele said:
foreach $_ ($self->accessors()) {
print "$_\n";
my $value = $self->_accessor_class($_)->get($_);
^^ ^^
^^ ^^

[snip]
$self->accessors returns an array of accessor names

So far so fine.
$self->_accessor_class returns a hash ref to a class

Which happens to be... what?!?

A subclass of Class::Accessor.
And what does it expect as an argument?

An accessor name.
And what does it expect as an argument?

An accessor name.
But most importantly in the code above get() is not a method of $self,
but of the object _accessor_class($_).

Yes, $self is an aggregated class and the get methods are different for
each aggregated class.

Class_B <---has a---$self----has a---> Class_A
| |
v v
sub get() sub get()
All in all it seems *strange*, although not strictly impossible, that
you want to pass $_ to both methods above.

$self uses the name of the accessor (_accessor_class) to determine
which aggregated class has the proper get function. get takes the
accessor name to know which value to get.
Also the fact that
accessors() returns an array of accessor names suggest that you are
fiddling with symrefs. You may return proper $method refs, and call
them like thus instead:

my $value = $self->$method(...);

I suppose calling:

get('accessor_name')

is essentially like using a symref but I think this is what would be
what would be considered a true symref call:

foreach $_ ($self->accessors()) {
my $value = $self->_accessor_class($_)->$_;
}

The only other way I can think of to handle this would be to return a
hash of method references from the accessors() function:

foreach $_ ($self->accessors()) {
my $value = $self->_accessor_class($_)->{'$_'};
}

and isn't that exactly what a class hash reference is in Perl?

I apologize for not being verbose enough with my example but I didn't
want to put 300 lines of code in my message. 300 lines would have been
the concise version too.

Thanks for the help,
Derek Basch





OkbridgeDatabase::Gps->mk_accessors(OkbridgeDatabase::Gps->accessors());

sub accessors {
my @accessors = (
'password',
'user_id',
'first_login',
'last_login',



To make a long story short: hard to say anything without looking at
the rest of your code. So, as usual, may you prepare a suitable
minimal but complete example exhibiting the problem? Also you'd better
state more clearly what you're actually trying to do.


Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
.'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
 
M

Mumia W.

Note that the way I found this error was by trying to do this:

%accessors_values = map { $iter =>
$self->_accessor_class($iter)->get($iter) } $self->accessors();

The foreach above was my attempt to break the problem into smaller
units for testing.
So, you can solve this problem by not using the implicit iterator with
a foreach loop.

What I didn't mention was that the get function above uses a "while
<FILEHANDLE>"
loop. The "while <FILEHANDLE>" loop uses an implicit iterator and the
map function also uses an implicit iterator.

So, if you use map with an EXPR that uses the "while <FILEHANDLE>"
idiom the map implicit iterator value will be replaced with the "while
<FILEHANDLE>" implicit iterator value. You must use foreach instead of
map.

I hope that helps someone in the future :)

Derek Basch

Indeed it probably will; it'll remind people to use local ;-)

#!/usr/bin/perl

package Tryit;
use strict;
use warnings;

my @fun = map { get(); $_ } (1..4);
print "@fun\n";

sub get {
# What happens when you comment out the "local"
# below?
local $_;
while (<DATA>) {
last if /###/;
}
}

__DATA__
nothing here
### more hash marks ###
 
B

Ben Morrow

Quoth Michele Dondi said:
you want to pass $_ to both methods above. Also the fact that
accessors() returns an array of accessor names suggest that you are
fiddling with symrefs.

Methods are looked up by name at runtime, so they're effectively symrefs
anyway.
You may return proper $method refs, and call
them like thus instead:

my $value = $self->$method(...);

....but whay would be the advantage in doing so, except in rather weird
circumstances?

Ben
 
U

Uri Guttman

MW> Indeed it probably will; it'll remind people to use local ;-)

better if it reminds people to not use $_ all the time. with loops it is
much better to use a lexical var and then you never can have anything
like this happen. and your code becomes easier to read as you have a
named variable for each loop and it is lexical and never is seen by any
called subs or maps.

uri
 
D

Derek Basch

It seems that in the end you're more knowledgeable than I am, because
as above I don't have the slightest idea of what a "class hash
reference" could be. A class is a package. The only hash that comes to
mind speaking of the latter, is its stash. Or else objects are often
implemented by means of blessed hash references "containing" the data,
but that's just one implementation choice. In any case I'm not really
sure about what you're talking about and I must be missing something,
sorry!


I guess I should read up more on the differences between a package
stash and blessed hash references as objects. I had been thinking they
were the same thing but apparently they are not.

Thanks for the help everyone,
Derek Basch
 
B

Ben Morrow

[please attribute quotes]

Quoth "Derek Basch said:
I guess I should read up more on the differences between a package
stash and blessed hash references as objects. I had been thinking they
were the same thing but apparently they are not.

Don't worry about package stashes: they are an advanced topic that
you'll likely never need to worry about. The source of Michele's
confusion is that you are mixing up the terms 'class' and 'object'. What
you meant to say instead of 'a class hash reference' was 'a reference to
an object' or 'a reference to a blessed hash'. The former is preferable
as the fact that the object is implemented as a blessed hash is not (or
should not be) important to users of that object.

A class is a type of object. It is represented in Perl by its name,
either as a string or as a bareword. So in

my $fb = Foo::Bar->new;

'Foo::Bar' is a class. The ->new method will be passed the string
'Foo::Bar' as its first argument.

An object is an instance of a class: that is, an object is to a class as
'1' is to 'the integers'. If ->new in the above is a normal constructor,
then $fb will hold a reference to an object. Objects in Perl can only be
accessed through references to them.

An object responds to certain methods: these are defined in the class in
class-based OO systems (which Perl's is, usually). However, it is
important to realize that calling a method on an object and calling it
on the class are quite different operations; most methods can only be
called on one or the other.

Ben
 

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,586
Members
45,088
Latest member
JeremyMedl

Latest Threads

Top