Try to Guess the Problem

Ovid on 2006-10-03T12:52:34

A coworker called me over on a problem he was completely stumped by. His boss was completely stumped by it, too. The problem looked like this:

use Foo;
my $foo = Foo->new;

Which resulted in the error Can't call method "new" on an undefined value.... I admit it had me stumped at first, but a quick session in the debugger and stepping through the code revealed the problem. Both 'strict' and 'warnings' were enabled, so the problem is not related to that.


No fair

jdavidb on 2006-10-03T12:58:07

I haven't gotten done guessing the last problem, yet!

Is the problem apparent from the code snippet you posted, alone?

Re:No fair

Ovid on 2006-10-03T13:10:25

The problem is caused by something else and that something else is not in Foo.pm. But once you realize what's going on, you'll slap your forehead and say "of course!"

__

Abigail on 2006-10-03T13:17:45

If there's a subroutine called Foo that returns an undefined value, you get that error message.
sub Foo {}
use Foo;
my $foo = Foo -> new;

__END__
Can't call method "new" on an undefined value at...

Re:__

Ovid on 2006-10-03T14:13:07

Yup. I was called over to look at the problem and it simply didn't occur to me that someone would name a sub after a package name.

Re:__

Aristotle on 2006-10-03T14:31:31

Despite the fact that you are the author of aliased?

Re:__

Ovid on 2006-10-03T15:21:23

With aliased, the sub is not the package name -- it's a shorter version -- and in any event, because it has a null prototype, it gets inlined away and no subroutine is left in the symbol table.

However, that's still a pretty lame defense on my part :)

Re:__

Aristotle on 2006-10-03T20:54:11

the sub is not the package name – it’s a shorter version

Yeah, but it’s used like a package name, on the left side of an arrow operator.

it gets inlined away and no subroutine is left in the symbol table.

Not at all. It gets inlined into calls, but the subroutine is always there.

Re:__

jonasbn on 2006-10-07T14:05:07

This is the way you do constructors in PHP4

Ref: http://dk.php.net/manual/en/language.oop.php

If anybody wonders as to why somebody would do it in the first place...

Without reading the other comments...

Alias on 2006-10-03T14:33:02

I'd say that as well as providing an Object-Oriented interface, for some strange reason, Foo.pm is also exporting a function called Foo() you can use directly.

Which is stupid of course, since now when doing OO you have to say

    Foo::->new;

The subroutine is found before the word is treating as a string (and thus class) and so Foo() returns undef, which gives your error.

I seem to recall encountering this during my AppSpace days a few times, with the end result I wrote a standard symbol table scanning unit test that would fail if it ever saw that specific subroutine/class clash.

I think the code might even be in Test::ClassAPI still, since that was spun out of that code...

Re:Without reading the other comments...

Abigail on 2006-10-03T20:48:56

No. If Foo.pm exports a sub Foo, there's no problem.

Re:Without reading the other comments...

Alias on 2006-10-04T06:13:25

Sorry?

The specific problem is function vs class name. Why does it matter where the subroutine comes from?

Specifically, if Foo contains sub Foo::Foo { undef } and exports it, what differs it from my defining sub Foo { undef } by hand?

What am I missing here? Something different about the *Foo glob?

Adam K