returning references, etc.

D

Dave

Hi,

I have one routine called "browserbuilder" which builds a moderately
complex LWP user agent, among other things. I want to be able to call
the browserbuilder sub from another routine and have browserbuilder
return the browser object to that subroutine. I then want that
subroutine to return the browser object when it is called from another
routine, which will end up using the browser object.

I clearly have something wrong, but I have not delt with objects and
references enough to figure out what. Can anyone tell me how to do it
correctly or point me in the right direction?

Thanks,
Dave
------------------------------------------------

I have a certain point in the browserbuilder subroutine right now that
looks like this:
if ($vlinkcall eq "yes")
{

$xbrowser->max_size(undef); # i built the rest of $xbrowser
elsewhere
return \$xbrowser; #$xbrowser is the name of my LWP::UserAgent
object
}

The command in the second subroutine, called "load_browser", which
calls the browserbuilder subroutine looks like this:

$browser=&browserbuilder($xurlid, $xusername, $xurl, $xtimezone,
$xauthusername, $xauthpassword, $xpostdata, $xcookieurl, $xrefurl,
$xtextstring1, $xtextstring2, $xaltcode, $xhackerchecksum, $i,
$xpalerts, $xsalerts, $xcheckrecovery, $xauthtype, $newchecksum,
$xlinkcall);

return \$browser;


The routine that needs the browser object uses this code:

$xbrowser=&load_browser($vurlid);
$xresponse= $xbrowser->get($murl);

The error message is:
Can't call method "get" on unblessed reference at ./simplelinks.cgi
line 80.
 
P

Paul Lalli

Dave said:
I have one routine called "browserbuilder" which builds a moderately
complex LWP user agent, among other things. I want to be able to call
the browserbuilder sub from another routine and have browserbuilder
return the browser object to that subroutine. I then want that
subroutine to return the browser object when it is called from another
routine, which will end up using the browser object.

I clearly have something wrong, but I have not delt with objects and
references enough to figure out what. Can anyone tell me how to do it
correctly or point me in the right direction?

Your central confusion seems to stem from not realizing that objects
*are* references. In general, you do not pass or return references to
objects; you pass and return the objects themselves.
I have a certain point in the browserbuilder subroutine right now that
looks like this:
if ($vlinkcall eq "yes")
{

$xbrowser->max_size(undef); # i built the rest of $xbrowser
elsewhere
return \$xbrowser; #$xbrowser is the name of my LWP::UserAgent
object
}

return $xbrowser;
The command in the second subroutine, called "load_browser", which
calls the browserbuilder subroutine looks like this:

$browser=&browserbuilder($xurlid, $xusername, $xurl, $xtimezone,
$xauthusername, $xauthpassword, $xpostdata, $xcookieurl, $xrefurl,
$xtextstring1, $xtextstring2, $xaltcode, $xhackerchecksum, $i,
$xpalerts, $xsalerts, $xcheckrecovery, $xauthtype, $newchecksum,
$xlinkcall);

Don't call subroutines using the & in front of the subroutine name
unless you know what that does and you want that added functionality.
99% of the time, you don't.
return \$browser;

return $browser;
The routine that needs the browser object uses this code:

$xbrowser=&load_browser($vurlid);
$xresponse= $xbrowser->get($murl);

The error message is:
Can't call method "get" on unblessed reference at ./simplelinks.cgi
line 80.

The problem is that at this point in your code, $xbrowser is a
reference to the object, not the object itself.

An example that eliminates the object-layer of confusion:

my @array = (1..10);
my $ref = \@array;
my $refref = \$ref;

$refref is a reference to a reference to an array. If you attempted to
access the first element of the array (as you were attempting to access
a method earlier) by using:
print "First element: $refref->[0]\n";
you would get the error "Not an ARRAY reference".

Once you understand the problem with the above example, it is easily
translated to your original problem by understanding that all Perl
objects *are* references (usually, but not always, references to
hashes). They are simply references that happen to have been blessed
into a class.

Hope this helps,
Paul Lalli
 
D

Dave Weaver

I have a certain point in the browserbuilder subroutine right now that
looks like this:
if ($vlinkcall eq "yes")
{

$xbrowser->max_size(undef); # i built the rest of $xbrowser
elsewhere

By the look of it (but I can't be sure because you've not shown the
relevant code), here $xbrowser is a blessed reference (i.e. an
'object').

I reccommend you find the posting guidelines that are posted here
regularly; they'll provide you with some great tips on how to get
the best answers from this group. One such tip is to post a *short*
but *complete* program that exhibits your problem; this allows others
to cut-and-paste the code and see the problem for themselves.
return \$xbrowser; #$xbrowser is the name of my LWP::UserAgent

Here you return a reference to that reference.
I suspect this should be
return $xbrowser;

object
}

The command in the second subroutine, called "load_browser", which
calls the browserbuilder subroutine looks like this:

$browser=&browserbuilder($xurlid, $xusername, $xurl, $xtimezone,
^
This & is superfluous here; if you don't know what its effects are,
you don't need it;
$browser = browserbuilder($xurlid, $xusername, $xurl, $xtimezone,
$xauthusername, $xauthpassword, $xpostdata, $xcookieurl, $xrefurl,
$xtextstring1, $xtextstring2, $xaltcode, $xhackerchecksum, $i,
$xpalerts, $xsalerts, $xcheckrecovery, $xauthtype, $newchecksum,
$xlinkcall);

return \$browser;

Here, again, you're returning a refernce to what is presumably
(although I can't be sure because you've just posted semi-random
snippets of code) also a blessed reference.

return $broswer;
The routine that needs the browser object uses this code:

$xbrowser=&load_browser($vurlid);

So now, if I understand your description of your code correctly,
$xbrowser is a reference to a reference to a blessed reference...

$xresponse= $xbrowser->get($murl);

The error message is:
Can't call method "get" on unblessed reference at ./simplelinks.cgi
line 80.

That's because $xbrowser isn't a blessed reference;
it's a reference to a reference to one.

Descriptions of error messages can be found in "perldoc perldiag"
 
D

Dave

Hi,

Thanks for your help. Per your suggestion, I broke down the code into a
small program that could be copied and pasted. I ran it and to my
surprise it worked how I thought it should.

Why is it that I would not want to use '&' when calling subroutine
names? It is a habit I've gotten into for no rhyme or reason. What does
it do?

Thanks for helping me break this down more. I pasted the code below in
case you wanted to see it.

~dave
-----------------------
#!/usr/bin/perl
use LWP;

&sub3; # I want to see a status code printed

sub sub1
{
my $xbrowser=LWP::UserAgent->new(
'agent' => "UltraUptime/1.0 (compatible; MSIE 6.0;
Windows NT 5.1)",
'max_size' => "1024",
'timeout' => "30",
'keep_alive' => 1
);
return $xbrowser;
}
sub sub2
{
$browser2=&sub1;
return $browser2;
}
sub sub3
{
$browser3=&sub2;
$xresponse= $browser3->get('http://www.yahoo.com');
print "HTTP Response: " . $xresponse->code() . "\n";
}

#my @array = (1..10);
#my $ref = \@array;
#my $refref = \$ref;
#print "First element: $refref->[0]\n";
 
P

Paul Lalli

Dave said:
Thanks for your help. Per your suggestion, I broke down the code into a
small program that could be copied and pasted. I ran it and to my
surprise it worked how I thought it should.

I'm confused by your surprise. Two different people told you what you
were doing wrong, and how to correct it. You made the appropriate
corrections. Had you assumed we were lying to you?
Why is it that I would not want to use '&' when calling subroutine
names? It is a habit I've gotten into for no rhyme or reason. What does
it do?

perldoc perlsub

It has two effects:
1) If called without any explicit parameters (ie, &myfunc;), will
automatically pass the current value of @_ as parameters.
2) Disables prototype checking. Prototypes are completely ignored if &
is used.

Paul Lalli
 
D

Dave

Hi Paul,

I certainly did not think anyone was misleading me. I thought I had
tried it like that the first time. That's how I assumed it should be
done. When it didn't work I started doing wacky things. After reading
your responses, I broke it down back to what I thought I had tried
initially without re-reading your responses in depth. I wanted to get
the error to happen in a small block of code so I could re-read the
responses in depth and fix it. My surprise was that it worked the first
time, not that I was provided correct, useful information :)

Thanks again for your help! I really appreciate it.
~dave
 
A

A. Sinan Unur

I broke it down back to what I thought I had tried
initially without re-reading your responses in depth. I wanted to get
the error to happen in a small block of code so I could re-read the
responses in depth and fix it. My surprise was that it worked the first
time, not that I was provided correct, useful information :)

Which is why the posting guidelines strongly recommend you do this as part
of your efforts to solve the problem.

Sinan
 
B

Bertilo Wennergren

Paul Lalli:
Don't call subroutines using the & in front of the subroutine name
unless you know what that does and you want that added functionality.
99% of the time, you don't.

I'll jump in on a tangent here:

I've tried to do things like you say, calling subroutines without "&", but
lately I've had the compiler sometimes complain about the wrong number of
arguments (which was never true!), and I've found that the only solution
was to add a "&" to the subroutine call. This seems to happen most often in
regular expressions (with an "e" switch), but also in some other cases. I
have no idea what's going on here. Does anyone have an idea?

I'm sorry I don't have any actual code examples. When it happens I now
almost routinely add "&" and move on, never understanding why all of a
sudden the extra "&" was required.

If necessary maybe I'll be able to create an example.

(BTW, I always do "use strict.")
 
A

A. Sinan Unur

Paul Lalli:


I'll jump in on a tangent here:

I've tried to do things like you say, calling subroutines without "&",
but lately I've had the compiler sometimes complain about the wrong
number of arguments

I would be interested to see how you get perl to complain about an
incorrect number of arguments to a sub.

Are you using prototypes? If you are using prototypes, and need to
disable prototype checking to get the program to work properly, why are
you using prototypes?
I'm sorry I don't have any actual code examples. When it happens I now
almost routinely add "&" and move on, never understanding why all of a
sudden the extra "&" was required.

If necessary maybe I'll be able to create an example.

It is not necessary for our benefit. It might be necessary for you to be
able to understand what you are doing wrong.

Sinan
 
T

Tad McClellan

Bertilo Wennergren said:
Paul Lalli:


I'll jump in on a tangent here:

I've tried to do things like you say, calling subroutines without "&", but
lately I've had the compiler sometimes complain about the wrong number of
arguments (which was never true!),


You probably shouldn't be using prototypes either, they don't do
what most people expect them to do.

and I've found that the only solution
was to add a "&" to the subroutine call.


Which overrides prototypes, ie. it is in Paul's "one percent".

But you still probably shouldn't be using prototypes.

This seems to happen most often in
regular expressions (with an "e" switch),


There are no subroutines involved with regular expressions,
so you must have entered the Twilight Zone or something.

but also in some other cases. I
have no idea what's going on here. Does anyone have an idea?

I'm sorry I don't have any actual code examples.


We will be able to answer your question when you come up with one,
until then there is no telling...

When it happens I now
almost routinely add "&" and move on, never understanding why all of a
sudden the extra "&" was required.


Because you are (attempting to) use prototypes on your function definitions.

Cargo cult programming is just plain silly!
 
S

Sherm Pendley

Bertilo Wennergren said:
I've tried to do things like you say, calling subroutines without "&", but
lately I've had the compiler sometimes complain about the wrong number of
arguments (which was never true!), and I've found that the only solution
was to add a "&" to the subroutine call.

When your car's "check engine" light comes on, would you consider the problem
solved if the mechanic simply disconnected the light without diagnosing the
cause of the problem? That's what you're doing here.

Using "&" disables prototype checking. That's where you declare a sub as
taking a specific number and type of arguments, like so:

sub foo($$) {
return "howdy\n";
}

print foo;

When I run this, I get:

test.pl:10: Not enough arguments for main::foo near "foo;"

Which is clear enough - I've asked for two arguments, and not supplied any.

The correct solution to this is to prototype the correct number of arguments,
or if you'll be passing different numbers of arguments, just omit the proto-
type completely:

sub foo {
return "howdy\n";
}

print foo;

This produces the expected "howdy".

While there are occasionally perfectly good reasons to silence a warning that
you do understand, silencing a warning that you don't understand is never a
good idea.

Have a look at "perldoc perlsub" for details about declaring and calling
Perl functions.

sherm--
 
B

Bertilo Wennergren

Tad McClellan:
There are no subroutines involved with regular expressions,
so you must have entered the Twilight Zone or something.

I meant subroutine calls used in the replacement part of a substitution.
Sorry about the hazy (read "wrong") terminology:

$foo =~ s/what(ever)/subroutine($1)/ge;

Here's a stupid example:

#!/usr/bin/perl
use strict;
my $text = 'barbarian';
$text =~ s/(a[rn])/subroutine($1)/ge;
print "$text\n";
sub subroutine() {
my $t = shift;
if ($t =~ /r/) {
$t =~ s/a/r/g;
} elsif ($t =~ /n/) {
$t =~ s/a/n/g;
}
return $t;
}

This works (prints "brrbrrinn\n"), but sometimes when I do stuff like that
(not using any prototyping!), perl complains about the wrong number of
arguments making me scratch my head.

Actually, if I add "-w" to the first line of the above, I do get a weird
warning about prototypes:

main::subroutine() called too early to check prototype at test.pl line 5.

Why do I get that warning? It should mean that I've called a function that
has a prototype before the parser saw a definition or declaration for it.
But I haven't used any prototyping in that code. (Or I've completely
misunderstood what prototyping is. That should be no wonder, since I never
- consciously - use prototyping.)
We will be able to answer your question when you come up with one,
until then there is no telling...

You're right of course. I'll try to whip up something that actually makes
the compiler complain. That's a bit hard though, since I've never
understood the circumstances.
 
B

Bertilo Wennergren

Sherm Pendley:
When your car's "check engine" light comes on, would you consider the
problem solved if the mechanic simply disconnected the light without
diagnosing the cause of the problem? That's what you're doing here.

I know. That's why I'm asking now. I've tried (using the documentation,
googling, etc) to find out what I'm actually doing wrong. But so far I've
gotten nowhere.
Have a look at "perldoc perlsub" for details about declaring and calling
Perl functions.

OK. Suddenly I lightbulb. I'm in the habit of writing my subroutines like
this:

sub whatever() { ... }

Now I realise that's probably a bad habit picked up from writing Javascript
code. If I understand right, putting in the parentheses actually means
using prototyping. I didn't know that. I thought putting dollar signs etc
inside the parentheses did that. This explains almost everything. I should
have used "-w" a lot more (hangs head in shame...).

But now I don't understand why I only get a warning (most of the time).
Shouldn't I get a syntax error if I call such a subroutine using one or
more arguments? Doesn't "sub whatever()" mean that I'm prototyping that sub
to use exactly zero arguments?

#!/usr/bin/perl -w
use strict;
my $text = 'barbarian';
$text = subroutine($text);
print "$text\n";
sub subroutine {
my $t = shift;
# whatever
return $t;
}

No syntax error, only a warning.

Anyway I'll stop using the useless parentheses. Thanks for your help!
 
B

Bertilo Wennergren

Sherm Pendley:
sub subroutine() {
[...]
This works (prints "brrbrrinn\n"), but sometimes when I do stuff like
that (not using any prototyping!)
The above *is* using a prototype - it's specified as taking no arguments.

Yes, I just found out what my use of parentheses actually means. I use them
only as a bad habit picked up from Javascript. I had no idea I was using
prototyping. (Never actually wanting to use prototyping, I never really
delved much into the subject.) I'll stop doing that now, of course.

But I don't understand why I only sometimes get an actual error when I call
such a badly declarated with an argument. It probably has something to do
with my always putting all the subroutines at the end of the code, but I
still can't make the whole puzzle fit.
 
J

John Bokma

Bertilo Wennergren said:
But I don't understand why I only sometimes get an actual error when I
call such a badly declarated with an argument. It probably has
something to do with my always putting all the subroutines at the end
of the code, but I still can't make the whole puzzle fit.

perldoc -f sub might be a great help instead of guessing, experimenting,
etc. The worst method of learning to program is trial and error: not
reading documentation and using "experience" from other languages,
especially if the latter is obtained in exactly the same way (which is
often the case, somehow).
 
S

Sherm Pendley

Bertilo Wennergren said:
But I don't understand why I only sometimes get an actual error when I call
such a badly declarated with an argument. It probably has something to do
with my always putting all the subroutines at the end of the code, but I
still can't make the whole puzzle fit.

That's exactly it. The compiler starts at the top of your code and compiles
to the end, so when it gets to a function call it's only aware of whatever
prototypes have been declared above the call. But that's just a warning, not
an error. It can still call the function, it just can't verify that the number
and type of arguments are correct.

For example, take this script:

#!/usr/bin/perl

use warnings;
use strict;

# foo() has not been prototyped at this point, so arguments aren't checked
print foo();

# Oops, foo() has a prototype now - but it's too late to go back and check
# that earlier call to foo().
sub foo() {
return "Howdy\n";
}

In addition to the expected "Howdy", it produces the following warning:

test.pl:6: main::foo() called too early to check prototype

You'll get a much more thorough description of the problem, and suggested
solutions, if you do "use diagnostics" instead of "use warnings".

There are two ways to deal with that. You could declare the sub above the
rest of the code. Or, you could forward declare the sub, like this:

#!/usr/bin/perl

use warnings;
use strict;

# Forward declare the subroutine foo() - define it later
sub foo();

print foo();

sub foo() {
return "Howdy\n";
}

If you've done any C/C++ programming, you'll feel right at home with this
declaration/definition split. If you've only done Java before this, you'll
find it bizarre beyond words. ;-)

sherm--
 
B

Bertilo Wennergren

Sherm Pendley:
That's exactly it. The compiler starts at the top of your code and
compiles to the end, so when it gets to a function call it's only aware of
whatever prototypes have been declared above the call. But that's just a
warning, not an error. It can still call the function, it just can't
verify that the number and type of arguments are correct.

Yes. That makes sense, and is more or less what I knew and expected. My last
problem was that I nevertheless sometimes got actual errors, not just
warnings. Having read your explanation, and having thought a bit more about
it, I believe I've found the last piece of the puzzle myself:

The times that I got actual errors were probably the times when used such
badly defined subroutines (prototyped due to my mistaken use of
parentheses) _in the replacement part of a substitution_. I such cases Perl
uses eval, and that means (as far as I can tell) that the compilation does
not happen as the compiler goes through the code from top to end (as you
put it), but afterwards as it gets to evaluate the replacement. If that's a
correct analysis, then everything makes sense to me now.
You'll get a much more thorough description of the problem, and suggested
solutions, if you do "use diagnostics" instead of "use warnings".

I'll start doing that. Thanks!
There are two ways to deal with that. You could declare the sub above the
rest of the code. Or, you could forward declare the sub, like this:
[...]
If you've done any C/C++ programming, you'll feel right at home with this
declaration/definition split. If you've only done Java before this, you'll
find it bizarre beyond words. ;-)

Actually Perl is my reference point for normality since Perl is the first
programming language I learnt. (Ss some would say my thinking is hoplessly
perverted from the start...) I've done some Java since, but no C(++) - and
a lot of Javascript which obviously has had some bad effects on my Perl-fu.

The problem is that I lernt Perl to a large extent by trial and error way
back then. It's only now, many years later, that I try to delve a little
deaper into things.

Thanks again for all the help!

John Bokma:
perldoc -f sub might be a great help instead of guessing, experimenting,
etc. The worst method of learning to program is trial and error: not
reading documentation and using "experience" from other languages,
especially if the latter is obtained in exactly the same way (which is
often the case, somehow).

I did read lots of documentation, but I still wasn't able to find the
answer, which turned out to involve quite a few subtle things - as well as
some old misunderstandings and bad habits of mine.

Actually I think it's impossible to solve things like this without some
guessing and experimenting in addition to reading the documentation. The
Perl documentation is sometimes not the easiest reading.
 
T

Tad McClellan

Bertilo Wennergren said:
Sherm Pendley:
sub subroutine() {
[...]
This works (prints "brrbrrinn\n"), but sometimes when I do stuff like
that (not using any prototyping!)
The above *is* using a prototype - it's specified as taking no arguments.

Yes, I just found out what my use of parentheses actually means. I use them
only as a bad habit picked up from Javascript.


Cargo cult programming is just plain silly!
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top