Perl overload #{} so that you can supply an object to foreach() - perl

Is there a way I can make a class overload the array dereferencer in such a way that I can supply an instance of that class to foreach and have a custom function run at every iteration?
I tried:
Overloading #{} and assigning it to a sub. However, in this case, the sub is only executed once and is supposed to return a reference to the array you want to iterate over. Almost but not quite what I wanted.
Overloading <>. This executes the assigned function with every read attempt. Exactly how I want it, however it works with a while loop and not with foreach.
overloading.pl
use overloaded;
$class = overloaded->new();
$class->add("Hi");
$class->add("Hello");
$class->add("Yeet");
foreach $string (#$class) {
print("NEXT ITEM: ".$string."\n");
}
while ($item = <$class>) {
print("NEXT ITEM: ".$item."\n");
}
overloaded.pm
package overloaded;
use strict;
use warnings;
use Data::Dumper;
use overload '#{}' => \&next, '<>' => \&fetchNext;
sub new {
my ($class, %args) = #_;
$args{fields} = ();
$args{pos} = 0;
return bless { %args }, $class;
}
sub add {
my ($self, $elem) = #_;
push(#{$self->{fields}}, $elem);
}
sub fetchNext {
my ($self) = #_;
print("reading next line...\n");
return $self->{fields}->[$self->{pos}++];
}
sub next {
my ($self) = #_;
print ("getting next array item\n");
return \#{$self->{fields}};
}
1;
output:
$ perl overloading.pl
getting next array item
NEXT ITEM: Hi
NEXT ITEM: Hello
NEXT ITEM: Yeet
reading next line...
NEXT ITEM: Hi
reading next line...
NEXT ITEM: Hello
reading next line...
NEXT ITEM: Yeet
reading next line...

The problem that you're having here is not the difference between #{...} and <...> but the difference between foreach and while.
A while loop acts a bit like an iterator in as much as its execution looks like this:
while (you can run a piece of code and get back a value) {
do something
}
So each time around the loop, it executes the piece of code in the while condition and expects to get a single value back. The code in the while condition is run in scalar context.
A foreach loop, on the other hand, only executes its code once and expects to get a list of values back. The code between parentheses at the start of the loop is executed in list context.
This is why you read a large file a line at a time using:
while (<$file_handle>) {
...
}
This only reads a single record from the file at a time. If you used a foreach loop instead like this:
foreach (<$file_handle>) {
...
}
then you would get all of the records back from the filehandle at once - which, obviously, takes far more memory.
Dereferencing an array reference works like that too. You get all of the values back at the same time. The overridden method (next()) will only be called once and will be expected to return a list of values.

I show some techniques in Object::Iterate. Give your object some methods to supply the next value and go from there.

[ This adds to Dave Cross's answer rather than being an answer on its own ]
Having a single iterator instance per collection cause all kinds of problem. That's why everyone uses keys instead of each, for example. As such, I strongly recommend that your class produces an iterator rather than being one itself, as the following does:
package My::Collection;
use strict;
use warnings;
use Iterator::Simple qw( iarray );
sub new {
my ($class) = #_;
my $self = bless({}, $class);
$self->{fields} = [];
return $self;
}
sub add {
my ($self, $elem) = #_;
push #{ $self->{fields} }, $elem;
}
sub iter {
my ($self) = #_;
return iarray($self->{fields});
}
1;
Use it as follows:
use strict;
use warnings;
use feature qw( say );
use My::Collection qw( );
my $collection = My::Collection->new();
$collection->add("Hi");
$collection->add("Hello");
$collection->add("Yeet");
my $iter = $collection->iter();
while ( my ($item) = $iter->next() ) {
say $item;
}
You can also use either of the following more magical options:
while ( my ($item) = $iter->() )
while ( my ($item) = <$iter> )

Related

Reference found where even-sized list expected in Perl - Possible pass-by-reference error?

I have a Perl class/module that I created to display Bible verses. In it there is a hash that stores several verses, with the key being the book/chapter/verse and the value being the text. This hash is returned from the module.
I'm including the Bible class in a controller class, and that connection seems to work. The problem is I keep getting errors on executing. My IDE because I'm following a Lynda tutorial, is Eclipse with the EPIC plugin.
The error is:
Reference found where even-sized list expected at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 42.
Use of uninitialized value $value in concatenation (.) or string at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 45.
HASH(0x19ad454) =>
Here is the CONTROLLER class:
#!/usr/bin/perl
# eh_bibleInspiration_controller.pl by Eric Hepperle - 06/23/13
#
use strict;
use warnings;
use Data::Dumper;
use EHW_BibleInspiration;
main(#ARGV);
sub main
{
my $o = EHW_BibleInspiration->new; # instantiate new object.
my %bo_ref = $o->getBibleObj();
print "\$o is type: " . ref($o) . ".\n";
print "\%bo_ref is type: " . ref(\%bo_ref) . ".\n";
# exit;
$o->getVerseObj();
listHash(\%bo_ref);
message("Done.");
}
sub message
{
my $m = shift or return;
print("$m\n");
}
sub error
{
my $e = shift || 'unkown error';
print("$0: $e\n");
exit 0;
}
sub listHash
{
my %hash = #_;
foreach my $key (sort keys %hash) {
my $value = $hash{$key};
message("$key => $value\n");
}
}
Here is the class that returns the verses and has the method to pick a random verse:
# EHW_BibleInspiration.pm
# EHW_BibleInspiration.
#
package EHW_BibleInspiration;
use strict;
use warnings;
use IO::File;
use Data::Dumper;
our $VERSION = "0.1";
sub new
{
my $class = shift;
my $self = {};
bless($self, $class); # turns hash into object
return $self;
}
sub getVerseObj
{
my ($self) = #_;
print "My Bible Verse:\n";
my $verses = $self->getBibleObj();
# get random verse
#$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};
# sub mysub {
# my $params = shift;
# my %paramhash = %$params;
# }
# my %verses = %{$verses};
# my $random_value = %verses{(keys %verses)[rand keys %verses]};
# print Dumper(%{$random_value});
}
sub getBibleObj
{
my ($self) = #_;
# create bible verse object (ESV)
my $bibleObj_ref = {
'john 3:16' => 'For God so loved the world,that he gave his only Son, that whoever believes in him should not perish but have eternal life.',
'matt 10:8' => 'Heal the sick, raise the dead, cleanse lepers, cast out demons. You received without paying; give without pay.',
'Luke 6:38' => 'Give, and it will be given to you. Good measure, pressed down, shaken together, running over, will be put into your lap. For with the measure you use it will be measured back to you.',
'John 16:24' => 'Until now you have asked nothing in my name. Ask, and you will receive, that your joy may be full.',
'Psalms 32:7' => 'You are a hiding place for me; you preserve me from trouble; you surround me with shouts of deliverance. Selah',
'Proverbs 3:5-6' => 'Trust in the LORD with all your heart, and do not lean on your own understanding. 6 In all your ways acknowledge him, and he will make straight your paths.',
'John 14:1' => 'Let not your hearts be troubled. Believe in God; believe also in me.'
};
my $out = "The BIBLE is awesome!\n";
return $bibleObj_ref;
}
1;
What am I doing wrong? I suspect it has something to do with hash vs hash reference, but I don't know how to fix it. My dereferencing attempts had failed miserably because I don't really know what I'm doing. I modeled my random getter off of something I saw on perlmonks. #$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};
In the main, you have:
my %bo_ref = $o->getBibleObj();
but, in package EHW_BibleInspiration;, the method getBibleObj returns : return $bibleObj_ref;
You'd do, in the main : my $bo_ref = $o->getBibleObj();
and then call listHash($bo_ref);
Finaly, don't forget to change sub listHash to:
sub listHash
{
my ($hash) = #_;
foreach my $key (sort keys %{$hash}) {
my $value = $hash->{$key};
message("$key => $value\n");
}
}
In your main, you do
listHash(\%bo_ref);
This passes a hash reference to the sub. However, it tries to unpack its arguments like
my %hash = #_;
Oops, it wants a hash.
Either, we pass it a hash: listHash(%bo_ref). This saves us much typing.
Or, we handle the reference inside the sub, like
sub listHash {
my ($hashref) = #_;
foreach my $key (sort keys %$hashref) {
my $value = $hashref->{$key};
print "$key => $value\n";
}
}
Notice how the reference uses the dereference arrow -> to access hash entries, and how it is dereferenced to a hash for keys.
I suspect that your suspicion is correct. In your method sub listHash you're correctly passing in the hash but you're trying to use a hash instead of a hash reference for the internal variable. Try using my ($hash) = #_; instead of my %hash = #_;.
When using references you can use the -> operator to de-reference it to get to the underlying values. The rest of your method should look like this:
sub listHash
{
my ($hash) = #_;
foreach my $key (sort keys %{$hash}) {
my $value = $hash->{$key};
message("$key => $value\n");
}
}
On line 43 of your program I had to tell Perl that the reference should be a hash reference by calling keys %{$hash}. Then on line 44 I de-referenced the hash to get the correct value by calling $hash->{$key}. For more information on Perl and references you can read the through the tutorial.
listHash is expecting a hash and you're passing it a hash reference. Change:
listHash(\%bo_ref);
to:
listHash(%bo_ref);

implement a node list in Perl

I wrote the following module but am not sure how to refer to the "last" and "head" nodes. As well as storing the address of the next node in "{nextNode}" in the previous node.
I am trying to save the reference of the class when storing it but later it's complaining: "Not a HASH reference at List.pm"; which I understand why but am not sure how the syntax would be.
If I de-reference $head and $last ($$last->{nextNode} = \$class) then I think it's using the actual name of my class; List and not the previous object like I want to.
package List;
my $head = undef;
my $last = undef;
sub new {
my $class = shift;
# init the head of the list
if ($head == undef) {
$head = \$class;
print "updated head to:$head", "\n";
}
$last = \$class;
$last->{nextNode} = \$class; # update previous node to point on this new one
print "updated last to:$last", "\n";
my $self = {};
$self->{value} = shift;
$self->{nextNode} = ""; # reset next to nothing since this node is last
return bless $self, $class;
}
Thanks guys
You should be storing $self everywhere instead of \$class. Storing $class is simply storing the name of the class, not the object itself.
Also, for $self->{nextNode} I'd store an undef instead of a blank string. Or better yet, simply don't create it at all and use exists when checking if it is there.
You're over thinking it. If you use an array for your list instead of a hash, you don't need to worry about the head and last. The head of an array is $array[0] and the last member is $array[-1]. Simple and easy to do.
Here's a quick standard class definition for defining a list. I've only defined a constructor (the new subroutine) and one method (the list).
package Local::List;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
$self->list([]);
}
sub list {
my $self = shift;
my $list_ref = shift;
if (ref $list_ref ne "ARRAY) {
return;
}
if (defined $list_ref) {
$self->{LIST} = $list_ref;
}
if wantarray {
return $self->{LIST};
}
}
The first thing: Use the same standard names everyone else uses. Use new for the constructor. When I try to look at the documentation on how to use your class, I can search for the word new and know that's how I create a class object. Also, use the variable names $class and $self. That's what everyone else does, so it's easy to know what's going on.
Notice in my new subroutine, the first item passed is the name of the class while the first item passed to my other subroutines is a reference to my class object (i.e. $self). That's probably the hardest thing to understand about classes.
Notice in new, I immediately create my $self and bless it. That way, I can call my other subroutines (my methods) to do the setting for me. This way, my constructor doesn't know how my class is structured. This has a lot of advantages:
When (not if) I modify my class, I don't have to modify the constructor.
My constructor is always in sync with all of my methods.
I don't have to know how my class object is structured when I start defining the class. I can start writing my class without worrying about all those dirty details on how it'll work.
Notice that the list subroutine (or method) can either set a list or return a list. It's much easier if you use the same subroutine to set or get the value. Also in your method subroutines, use a blank return when your method function returns an error. Otherwise, always return something. That makes it easy to test to see if a method failed or not.
Let's look at some of the other methods you probably want to have. Let's have all the four standard list functions:
push
pop
shift
unshift
Here's an example:
sub push {
my $self = shift;
my $member = shift;
if (not defined $member) {
return;
}
my $list_ref = $self->list;
my $return = push #{ $list_ref }, $member;
$self->list($list_ref);
return $return;
}
Wow, that's simple. Notice that the pop doesn't know what my class looks like. It used the list method to retrieve a list reference. Then it used the builtin push method to push a member onto the list. I save that return value, and that's what I'll return. I'm not even sure what push returns. All I know is that push returns something if it succeeds. (Yes, I know it returns the number of items in the list).
The other three functions are more or less the same. Here's a few more:
current
splice
next
previous
head
last
All you need to do for current is to store the current value. Use the same function to set and get the value. Notice that my list method or my push method, or my new constructor knows or care how you store it. Nor, do our next and previous methods. All they need to do is increment or decrement the value of current and store it back using the current method subroutine:
sub next {
my $self = shift
my #list = $self->list; #Returns a list;
my $current = $self->current;
my $list_size = $#list;
if ($current eq $list_size) {
return; #Can't return a value after the end of the list!
}
$current++; #Increment the value;
my $value = $list[$current]; #I'll return this
$self->current($current) #Store the new current
return $value;
}
And, now to the basis of your question: Getting the last and head values of the list. Here's last
sub last {
my $self = shift;
my $list_ref = $self->list;
return ${ $list_ref }[-1];
}
And a quick copy and paste will give me head:
sub head {
my $self = shift;
my $list_ref = $self->list;
return ${ $list_ref }[0];
}
That's it! All that worrying you were doing was for naught.
Sorry for the long post. I just wanted to emphasize that object oriented programming in Perl isn't that tricky as long as you follow a few simple guide lines.
(Simple? What about use Moose; No, I said simple!). ;-)
I just want to post my final working version for the record and for your feedback/comments.
Thanks again!!
package List;
my $head = undef;
my $last = undef;
sub new {
my ($class, $val) = #_;
my $self = {};
# init the head of the list
if (!defined $head) {
$head = $self;
print "updated the head of the list ($head)" . "\n";
}
else {
$last->{nextNode} = $self; # update previous node to point on this new one
}
$last = $self; # this object is now the last one
$self->{value} = $val; # store the value
$self->{nextNode} = undef; # reset next to nothing since this node is last
return bless $self, $class;
}
sub setVal {
my ($class, $val) = #_;
$class->{value} = $val;
}
sub getVal {
my $class = shift;
print $class->{value};
}
sub getNext {
my $class = shift;
return $class->{nextNode};
}
# return true if this is the last node, otherwise false.
sub isLast {
my $class = shift;
return 1 if !defined $class->{nextNode};
return 0;
}
sub getLast {
return $last;
}
sub getHead {
return $head;
}
# looping through all the list and printing the values
sub showList {
my $node = $head; # set temp node to the head
while ( !$node->isLast() ) {
print $node->{value} . "\n";
$node = $node->{nextNode};
}
# printing last value. (should be defined but I check it just in case)
print $node->{value} . " (last)\n" if defined $node->{value};
}
1;
Script:
my $n0 = new List(4);
my $n1 = new List(8);
my $n2 = new List(9);
my $n3 = new List(3);
my $n4 = new List(1);
my $n5 = new List(0);
my $n6 = new List(5);
print "\nShow list: \n";
$n2->showList(); # any object will print the list

In Perl, how can a subroutine get a coderef that points to itself?

For learning purposes, I am toying around with the idea of building
event-driven programs in Perl and noticed that it might be nice if a
subroutine that was registered as an event handler could, on failure,
just schedule another call to itself for a later time. So far, I have
come up with something like this:
my $cb;
my $try = 3;
$cb = sub {
my $rc = do_stuff();
if (!$rc && --$try) {
schedule_event($cb, 10); # schedule $cb to be called in 10 seconds
} else {
do_other_stuff;
}
};
schedule_event($cb, 0); # schedule initial call to $cb to be performed ASAP
Is there a way that code inside the sub can access the coderef to that
sub so I could do without using an extra variable? I'd like to
schedule the initial call like this.
schedule_event( sub { ... }, 0);
I first thought of using caller(0)[3], but this only gives me a
function name, (__ANON__ if there's no name), not a code reference
that has a pad attached to it.
__SUB__ has been added in 5.16, providing this usability.
I think Sub::Current will fix your problem.
To get a reference to the current subroutine without using an extra variable, you can use a tool from functional programming, the Y-combinator, which basically abstracts away the process of creating the closure. Here is a perlish version:
use Scalar::Util qw/weaken/;
sub Y (&) {
my ($code, $self, $return) = shift;
$return = $self = sub {$code->($self, #_)};
weaken $self; # prevent a circular reference that will leak memory
$return;
}
schedule_event( Y { my $self = shift; ... }, 0);
If you don't change $cb's value again, you can use that. If not, define a scalar to hold that and don't change it ever again. For example:
my $cb = do {
my $sub;
$sub = sub { contents using $sub here }
}
Using a fixed-point combinator, you can write your $cb function as if the first argument was the function itself:
sub U {
my $f = shift;
sub { $f->($f, #_) }
}
my $cb = sub {
my $cb = shift;
...
schedule_event(U($cb), 10);
...
}
schedule_event(U($cb), 0);

In Perl, how can I call a method whose name I have in a string?

I'm trying to write some abstract code for searching through a list of similar objects for the first one whose attributes match specific values. In order to do this, I need to call a bunch of accessor methods and check all their values one by one. I'd like to use an abstraction like this:
sub verify_attribute {
my ($object, $attribute_method, $wanted_value) = #_;
if ( call_method($object, $attribute_method) ~~ $wanted_value ) {
return 1;
}
else {
return;
}
}
Then I can loop through a hash whose keys are accessor method names and whose values are the values I'm looking for for those attributes. For example, if that hash is called %wanted, I might use code like this to find the object I want:
my $found_object;
FINDOBJ: foreach my $obj (#list_of_objects) {
foreach my $accessor (keys %wanted) {
next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor});
}
# All attrs verified
$found_object = $obj;
last FINDOBJ;
}
Of course, the only problem is that call_method does not exsit. Or does it? How can I call a method if I have a string containing its name? Or is there a better solution to this whole problem?
my $found_object;
FINDOBJ: foreach my $obj (#list_of_objects) {
foreach my $accessor (keys %wanted) {
next FINDOBJ unless $obj->$accessor() == $wanted{$accessor};
}
# All attrs verified
$found_object = $obj;
last;
}
Yes, you can call methods this way. No string (or any other) eval involved.
Also, substitute == with eq or =~ depending on the type of the data...
Or, for some extra credits, do it the functional way: (all() should really be part of List::Util!)
use List::Util 'first';
sub all (&#) {
my $code = shift;
$code->($_) || return 0 for #_;
return 1;
}
my $match = first {
my $obj = $_;
all { $obj->$_ == $attrs{$_} }
keys %wanted
} #list_of_objects;
Update: Admittedly, the first solution is the less obfuscated one, so it's preferable. But as somebody answering questions, you have add a little sugar to make it interesting for yourself, too! ;-)
Functional way is cool, but for dummies like me eval rules:
test.pl
#!/usr/bin/perl -l
use F;
my $f = F->new();
my $fun = 'lol'; # method of F
eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var
F.pm
package F;
sub new
{
bless {};
}
sub lol
{
print "LoL";
}
1;
[root#ALT-24 root]# perl test.pl
LoL

How can I code in a functional style in Perl?

How do you either:
have a sub return a sub
or
execute text as code
in Perl?
Also, how do I have an anonymous function store state?
A sub returns a sub as a coderef:
# example 1: return a sub that is defined inline.
sub foo
{
return sub {
my $this = shift;
my #other_params = #_;
do_stuff();
return $some_value;
};
}
# example 2: return a sub that is defined elsewhere.
sub bar
{
return \&foo;
}
Arbitrary text can be executed with the eval function: see the documentation at perldoc -f eval:
eval q{print "hello world!\n"};
Note that this is very dangerous if you are evaluating anything extracted from user input, and is generally a poor practice anyway as you can generally define your code in a coderef as in the earlier examples above.
You can store state with a state variable (new in perl5.10), or with a variable scoped higher than the sub itself, as a closure:
use feature 'state';
sub baz
{
state $x;
return ++$x;
}
# create a new scope so that $y is not visible to other functions in this package
{
my $y;
sub quux
{
return ++$y;
}
}
Return a subroutine reference.
Here's a simple example that creates sub refs closed over a value:
my $add_5_to = add_x_to(5);
print $add_5_to->(7), "\n";
sub add_x_to {
my $x = shift;
return sub { my $value = shift; return $x + $value; };
}
You can also work with named subs like this:
sub op {
my $name = shift;
return $op eq 'add' ? \&add : sub {};
}
sub add {
my $l = shift;
my $r = shift;
return $l + $r;
}
You can use eval with an arbitrary string, but don't do it. The code is hard to read and it restarts compilation, which slows everything down. There are a small number of cases where string eval is the best tool for the job. Any time string eval seems like a good idea, you are almost certainly better off with another approach.
Almost anything you would like to do with string eval can be achieved with closures.
Returning subs is easy by using the sub keyword. The returned sub closes over the lexical variables it uses:
#!/usr/bin/perl
use strict; use warnings;
sub mk_count_from_to {
my ($from, $to) = #_;
return sub {
return if $from > $to;
return $from ++;
};
}
my $c = mk_count_from_to(-5, 5);
while ( defined( my $n = $c->() ) ) {
print "$n\n";
}
5.10 introduced state variables.
Executing text as Perl is accomplished using eval EXPR:
the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program, so that any variable settings or subroutine and format definitions remain afterwards. Note that the value is parsed every time the eval executes
Executing arbitrary strings will open up huge gaping security holes.
You can create anonymous subroutines and access them via a reference; this reference can of course be assigned to a scalar:
my $subref = sub { ... code ... }
or returned from another subroutine
return sub { ... code ... }
If you need to store states, you can create closures with lexical variables defined in an outer scope like:
sub create_func {
my $state;
return sub { ... code that can refer to $state ... }
}
You can run code with eval