Using "Perl Best Practices" inside-out objects

  • Thread starter mhearne808[insert-at-sign-here]gmail[insert-dot-he
  • Start date
M

mhearne808[insert-at-sign-here]gmail[insert-dot-he

All: I'm having trouble returning an array from a class implemented
using Damian Conway's inside-out object approach.

Below are two snippets of code:
1) The test script where I am attempting to retrieve an array from an
inside-out attribute from an object.
2) The test class.

I think the main problem is on the line where I am assigning an array
to one of these inside out attributes. Somehow I think the attribute
is only getting the last element of the array that I am attempting to
assign it to.

I would have tested Conway's code verbatim, except that the
File::System->list_files() method in his text does not seem to exist.
I assume from context that list_files() returns an array of files...

Does anyone have (simple) examples of inside-out classes with a method
that returns an array?

#Test script
use PAGER::Test;
use strict;

my $test = PAGER::Test->new();
my @array = $test->getData();
my $n;
foreach $n (@array){
print "$n\n";
}
#end of test script

#Test module
#!/usr/bin/perl

package MYPACKAGE::Test;
use Class::Std::Utils;
use strict;
{
my %data; #the absolute path where pager.pl is located

sub new{
my ($class) = @_;
my $new_object = bless anon_scalar(),$class;
$data{ident $new_object} = (1,2,3,4,5);
return $new_object;
}

sub getData{
my ($self) = @_;
return @{$data{ident $self}};
}

sub DESTROY{
my ($self) = @_;
delete $data{ident $self};
return;
}
}
1;
#end of Test module
 
P

Paul Lalli

All: I'm having trouble returning an array from a class implemented
using Damian Conway's inside-out object approach.

Below are two snippets of code:
1) The test script where I am attempting to retrieve an array from an
inside-out attribute from an object.
2) The test class.

I think the main problem is on the line where I am assigning an array
to one of these inside out attributes. Somehow I think the attribute
is only getting the last element of the array that I am attempting to
assign it to.

I snipped the class structure, because inside-out objects have nothing
at all to do with this problem. Giant Red Herring. The problem is
this line:

$data{ident $new_object} = (1,2,3,4,5);

If you print $data{ident $new_object}, you will see it contains the
value 5. That is because you cannot assign a list of values to a
scalar. What you're actually doing is using the comma operator in
scalar context. (see perldoc perlop for more info on that).

Instead, you need to assign a reference to an anonymous array to that
scalar value. The construct for creating such a reference is square
brackets, not parentheses.

$data{ident $new_object} = [ 1, 2, 3, 4, 5];

Once again, this has nothing to do with objects, be they 'normal' or
inside-out. This is the same issue as if you had errantly done:

my $foo = (1, 2, 3, 4, 5);
In that case, $foo would get the value 5. Whereas if you'd correctly
done:
my $foo = [1, 2, 3, 4, 5];
then $foo would get a reference to an anonymous array that contains
the values (1, 2, 3, 4, 5).

Hope this helps,
Paul Lalli
 
M

mhearne808[insert-at-sign-here]gmail[insert-dot-he

Paul - Thanks very much! I didn't know about the [] syntax for
creating references to arrays. I presume now that the mythical
list_files() method returns a reference to an array, not an array.
Might have been helpful if Conway had used a real method in his
example.

--Mike

All: I'm having trouble returning an array from a class implemented
using Damian Conway's inside-out object approach.
Below are two snippets of code:
1) The test script where I am attempting to retrieve an array from an
inside-out attribute from an object.
2) The test class.
I think the main problem is on the line where I am assigning an array
to one of these inside out attributes. Somehow I think the attribute
is only getting the last element of the array that I am attempting to
assign it to.

I snipped the class structure, because inside-out objects have nothing
at all to do with this problem. Giant Red Herring. The problem is
this line:

$data{ident $new_object} = (1,2,3,4,5);

If you print $data{ident $new_object}, you will see it contains the
value 5. That is because you cannot assign a list of values to a
scalar. What you're actually doing is using the comma operator in
scalar context. (see perldoc perlop for more info on that).

Instead, you need to assign a reference to an anonymous array to that
scalar value. The construct for creating such a reference is square
brackets, not parentheses.

$data{ident $new_object} = [ 1, 2, 3, 4, 5];

Once again, this has nothing to do with objects, be they 'normal' or
inside-out. This is the same issue as if you had errantly done:

my $foo = (1, 2, 3, 4, 5);
In that case, $foo would get the value 5. Whereas if you'd correctly
done:
my $foo = [1, 2, 3, 4, 5];
then $foo would get a reference to an anonymous array that contains
the values (1, 2, 3, 4, 5).

Hope this helps,
Paul Lalli
 
P

Paul Lalli

I snipped the class structure, because inside-out objects have nothing
at all to do with this problem. Giant Red Herring. The problem is
this line:
$data{ident $new_object} = (1,2,3,4,5);
If you print $data{ident $new_object}, you will see it contains the
value 5. That is because you cannot assign a list of values to a
scalar. What you're actually doing is using the comma operator in
scalar context. (see perldoc perlop for more info on that).
Instead, you need to assign a reference to an anonymous array to that
scalar value. The construct for creating such a reference is square
brackets, not parentheses.
$data{ident $new_object} = [ 1, 2, 3, 4, 5];
Once again, this has nothing to do with objects, be they 'normal' or
inside-out. This is the same issue as if you had errantly done:
my $foo = (1, 2, 3, 4, 5);
In that case, $foo would get the value 5. Whereas if you'd correctly
done:
my $foo = [1, 2, 3, 4, 5];
then $foo would get a reference to an anonymous array that contains
the values (1, 2, 3, 4, 5).
Paul - Thanks very much! I didn't know about the [] syntax for
creating references to arrays.

You need to review a bunch of perliminary Perl information before you
start tackling objects (of any flavor). Please pause for a few
minutes and read:
perldoc perlreftut
perldoc perllol
perldoc perldsc
I presume now that the mythical
list_files() method returns a reference to an array, not an array.

Not necessarily. You can return an array from a subroutine just fine.

sub foo {
my $ref = [ 1, 2, 3, 4, 5 ];
return @{$ref};
}

my @stuff = foo();
Might have been helpful if Conway had used a real method in his
example.

I have no idea what "example" you're talking about. Can you give a
pointer to it? Is it in PBP? What chapter/page? Or is it online
somewhere?

Paul Lalli
 
C

Charlton Wilbur

PL> You need to review a bunch of perliminary Perl information

Great typo!

Charlton
 
M

Michele Dondi

PL> You need to review a bunch of perliminary Perl information

Great typo!

I (tend to) do it all the time. In Italian 'for' is 'per' and can be
followed by a word beginning with 'l', typically a determinative
article. Imagine what happens when I write "per la miseria!"


Michele
 
P

Peter Scott

I snipped the class structure, because inside-out objects have nothing
at all to do with this problem. Giant Red Herring.
[snip]

So is the implementation. I presume the OP is working through PBP, but
they may be unaware that they've only reached an intermediate stage of
inside-out object construction and that Conway is working toward using his
CPAN module Class::Std, where it won't be necessary for the user to write
a new() method, accessors, or destructor. Then an implementation of an
array-based attribute looks like:

#!perl
use strict;
use warnings;

package Foo;

use Class::Std;

my %thing :ATTR( :name<thing> :default<[]> );

sub things {
my $self = shift;
@{ $self->get_thing };
}

package main;

my $foo = Foo->new( { thing => [ qw(a b c) ] } );

print "$_\n" for $foo->things;
__END__

But as you later point out, the OP may need to master some more basic
concepts first.
 
M

Michele Dondi

my %thing :ATTR( :name<thing> :default<[]> );

I briefly heard about attributes, and I know I could read the docs,
but I hadn't seen that syntax yet: that is, angular parens. When were
they introduced? Where are they documented? (I know about their use in
Perl 6, but that's a whole another story.)


Michele
 
P

Paul Lalli

use Class::Std;

my %thing :ATTR( :name<thing> :default<[]> );

I'm 99% sure that doesn't work, as I tried it (albeit with standard
Perl 5 syntax) only last week. The default attribute can only take
strings. Array refs don't work. You need to provide a BUILD
subroutine in which you assign name to [].

Paul Lalli
 
P

Peter Scott

use Class::Std;

my %thing :ATTR( :name<thing> :default<[]> );

I'm 99% sure that doesn't work, as I tried it (albeit with standard
Perl 5 syntax) only last week. The default attribute can only take
strings. Array refs don't work. You need to provide a BUILD
subroutine in which you assign name to [].

Well it works for me :)

% cat foo
#!/usr/local/bin/perl
use strict;
use warnings;

package Foo;
use Class::Std;

my %thing :ATTR( :name<thing> :default<[3..5]> );

sub things {
my $self = shift;
@{ $self->get_thing };
}

package main;

my $foo = Foo->new;
print "$_\n" for $foo->things;
__END__

% ./foo
3
4
5

% perl -MClass::Std -le 'print VERSION Class::Std'
0.000008
 
P

Peter Scott

my %thing :ATTR( :name<thing> :default<[]> );

I briefly heard about attributes, and I know I could read the docs,
but I hadn't seen that syntax yet: that is, angular parens. When were
they introduced? Where are they documented? (I know about their use in
Perl 6, but that's a whole another story.)

perldoc Class::Std. They're completely peculiar to that module, because
it's parsing the argument of :ATTR itself. Parens and guillemots work
also, and fat comma syntax. Look in the source at the subroutine
_extractor_for_pair_named().
 
T

Tad McClellan

Paul Lalli said:
You can return an array from a subroutine just fine.


No you can't.

sub foo {
my $ref = [ 1, 2, 3, 4, 5 ];
return @{$ref};
}

my @stuff = foo();


You can return the _contents_ of an array (a list) from a
subroutine just fine.
 
M

Michele Dondi

my %thing :ATTR( :name<thing> :default<[]> );

I briefly heard about attributes, and I know I could read the docs,
but I hadn't seen that syntax yet: that is, angular parens. When were
they introduced? Where are they documented? (I know about their use in
Perl 6, but that's a whole another story.)

perldoc Class::Std. They're completely peculiar to that module, because
it's parsing the argument of :ATTR itself. Parens and guillemots work
also, and fat comma syntax. Look in the source at the subroutine
_extractor_for_pair_named().

I kinda understand: but then what's in the "argument" to an attribute
is considered a plain string, that can be parsed at one's will?


Michele
 
P

Paul Lalli

use Class::Std;
my %thing :ATTR( :name<thing> :default<[]> );
I'm 99% sure that doesn't work, as I tried it (albeit with standard
Perl 5 syntax) only last week. The default attribute can only take
strings. Array refs don't work. You need to provide a BUILD
subroutine in which you assign name to [].

Well it works for me :)

% cat foo
#!/usr/local/bin/perl
use strict;
use warnings;

package Foo;
use Class::Std;

my %thing :ATTR( :name<thing> :default<[3..5]> );

sub things {
my $self = shift;
@{ $self->get_thing };

}

package main;

my $foo = Foo->new;
print "$_\n" for $foo->things;
__END__

% ./foo
3
4
5

% perl -MClass::Std -le 'print VERSION Class::Std'
0.000008

Apparently it's only the Perl5 syntax that doesn't allow it. Changing
your line above to:
my %thing :ATTR( name => 'thing', default => [3..5] );

results in:
Missing initializer label for Foo: 'thing'.
Fatal error in constructor call at ./foo.pl line 18

$ perl -MClass::Std -le 'print VERSION Class::Std'
0.000008

Paul Lalli
 
P

Peter Scott

I kinda understand: but then what's in the "argument" to an attribute
is considered a plain string, that can be parsed at one's will?

Oh yes. perldoc attributes. Class::Std is using the native,
complicated way of parsing attributes directly rather than a helper module
like Attribute::Handlers. Look at MODIFY_type_ATTRIBUTES. In the case of
Class::Std programs, the type is HASH, and there is only one attribute in
the list, called 'ATTR'. Read further down: "...The parameter list is
passed as it was found, however..."
 
M

Michele Dondi

Oh yes. perldoc attributes. Class::Std is using the native,
complicated way of parsing attributes directly rather than a helper module
like Attribute::Handlers. Look at MODIFY_type_ATTRIBUTES. In the case of

TY


Michele
 

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,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top