develooper Front page | perl.perl5.porters | Postings from October 2007

Re: [perl #46987] OO-call failures, autoviv-functions & testing their existence

Thread Previous | Thread Next
From:
demerphq
Date:
October 29, 2007 17:04
Subject:
Re: [perl #46987] OO-call failures, autoviv-functions & testing their existence
Message ID:
9b18b3110710291704i1f20e236qd7b662dc5f196cfe@mail.gmail.com
On 10/30/07, Linda W <perl-diddler@tlinx.org> wrote:
> yves orton via RT wrote:
> > On 10/28/07, via RT Linda Walsh <perlbug-followup@perl.org> wrote:
> >> This is a bug report for perl from perl-diddler@tlinx.org,
> >> generated with the help of perlbug 1.35 running under perl v5.8.8.
> > [...]
> >>     my @dummy=(\&boom);                                         #ln 22
> > [...]
> >> The above prog demonstrates three (3) OO-call related problems.
> >> Perl autovivifies "\&boom" into "@dummy" in "sub laytrap" (ln 22,
> >> above). This *interferes* with OO calls through a blessed ref
> >> later on in program execution.
> >
> > IMO this isnt a bug. It may be confusing behaviour, but its not a bug.
> > It works just the same as the equivalent code would work with a hash.
> ---
>         Is referencing a "hash" guaranteed to check for references in a
> parent before returning failure for a non-local definition?

Referencing a subroutine is referencing a slot in a glob in the symbol
table. Symbol tables are hashes. Therefore this behavior is expected.
The fact that it results in behavior that you find suprising is more a
reflection of your (mis)understanding of how subroutine calls and
method calls work in a dyanmic language than it is an error in Perls
behaviour.

>         I don't think it is the same.  Part of OO functionality --
> a MAJOR part, is that if the "method" is not defined local, they it
> checks the parent classes.

Taking a reference to a subroutine does not involved method dispatch
and is NOT documented to take a reference to a parents subroutine.
Therefore it isnt a bug.

>         The error message tells the user "&localclass::method" isn't
> found in "$self->parentmethod;".  The user will think "I know that.  It is
> a parent method -- I wouldn't expect it to be in localclass.  Why doesn't
> it do the standard OO-lookup *before* returning "undefined".  If I
> DID NOT want an OO-call (that checks through parents), I could tell it
> to call the function as a local function.  Instead of
>      $self->method
> I'd use:
>      method($self).
>
> But using the method-call syntax "$self->method", it should look through
> the parent classes for the method *before* throwing the undefined-error.

No, you created a subroutine stub in the symbol table. Perl has to
assume that you did it for a reason. Perl doesnt know how that method
stub was created, and cant know that it was because you did something
silly and it should ignore it.

>
>
> > d:\>perl -e"my $x=\&foo; eval 'sub foo { warn qq(foo) }'; $x->()"
> > foo at (eval 1) line 1.
> >
> > d:\>perl -e"my %f; my $r=\$f{x}; $$r='testing'; print $f{x};"
> > testing
> >
> > The similarity in behavior is not unexpected, given that Perl's global
> > symbol tables are really just hashes in disguise.
> ----
>         BUT a hash table isn't something *DEFINED* to look in parent
> classes.  A method-call is.  They are not symmetric.

A method call is supposed to look at each entry in the current
package, failing finding one, it is supposed to look in  the parents
classes. You created one, albeit by an unusual route, and Perl found
it. You are muddying the water by bringing up method dispatch to
somehow make your incorrect autovivification seem less at fault here.

I mean, computers dont normally ignore things that programmers tell
them to do. When they do its generally considered a bug. You cant turn
around and say that in this case perl should know you didnt really
mean for it do something so it should just pretend you didnt.

>
>
> > The code you marked as #ln 22, and quoted above is the problem.
> > Essentially you are creating a function stub, which perl expects you
> > to fill in later, but you haven't filled it in. Since this produces
> > undesirable results you simply shouldn't do that.
> ----
>         Well this is the solution others come up with -- but no one
> even knew "why" until I reported the bug.  It's confusing and not
> behaving as the OO-language lookup is supposed to.

Well you were told several times that what you were doing was wrong.
So what if  nobody happened to hit on the exact explanation that would
have satisfied you? The advice we gave about how to do it right was
correct.

> > You should do something like
> >
> >    my @dummy; push @dummy,(\&boom) if defined *boom{CODE};     #ln 22
> >
> > which takes a reference to the sub only if it is actually defined.
> ----
>         That is yet ANOTHER great workaround.  That doesn't mean
> that a call, through a Blessed-ref shouldn't, *FIRST*, do the parental
> method lookup, before throwing the fatal error.  I would do the parental
> lookup just before throwing the "Undefined" error -- it doesn't have
> to be "optimized" -- just "work".

Thats nice. Too bad it doesn't match how it actually works, and given
that you don't seem to understand the deeper implications of working
in a dynamic language I don't think you are really in a good position
to determine how one should work.

>         This is another part that is "really wrong".  The user cannot
> rely on the built-in "can()" function to determine if the method is
> safe to call.  I tried to "protect" the calls -- but 'can' returns true
> if there has been a reference to the same-name, but undefined local
> function.  You can't use "defined($self->method)" as a replacement for
> $self->can('method');

There are two issues here. First, you shouldnt create function stubs
when you dont intend to fill them in. The fact that you did so by a
rather unusual mechanism is annoying I agree but is not wrong.

Second, you cant generally rely on references to subroutines,
regardless how they are obtained, through can() or other means, to do
the same thing as named dispatch would, be it named method dispatch,
or named subroutine dispatch.

Here is an example:

demerphq@gemini:~$ perl -le'  sub foo { print "foo" }
  foo();
  my $sub=\&foo;
  local *foo=sub { print "bar" };
  foo();
  $sub->();
'
foo
bar
foo

I say 'generally' here for  a reason BTW, under controlled
circumstances you can rely on its behavior, but your situation wasn't
really what I would consider a controlled circumstance.

>
>         I acknowledge that this is not as str8tforward a fix as one
> might like, but I believe this area is hit more often than the bug
> report numbers represent.  Too many perl-experts knew the workaround, but
> couldn't say WHY what I was doing failed.

You had reams of code, riddled with red flags. In fact the code I
analysed was plain and simply wrong, and method dispatch really had
nothing to do with it. Its no wonder no one hit on the exact reason
that would have satisfied you. If you had listened to the advice given
you instead of discounting it as superstitious then the problem would
have gone away. If you had managed to reduce it down to less than 10
lines of code *maybe* we would have hit on the explanation that would
have satisfied you, but sifting through 50 lines of code riddled with
red flags is no fun, especially when the person you are trying to help
argues with you about the red flags you point out.

>Narrowing down to the
> point where I could get others to understand the bug and to where
> felt I had a handle on it well enough to *report the bug*, took a bit
> of persistence.  I'd guess most people wouldn't bother to find the "root
> cause" let along get it to the point of filing it in a bug.

And its not a bug. And most people would have realized that and just
went "oh, ok, so that doesnt do what I expect" instead of "that should
do what I want it to do so it must be a bug because it doesn't".

Yves


-- 
perl -Mre=debug -e "/just|another|perl|hacker/"

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About