Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.98k stars 559 forks source link

OO-call failures, autoviv-functions & testing, existence #9088

Closed p5pRT closed 17 years ago

p5pRT commented 17 years ago

Migrated from rt.perl.org#46987 (status was 'resolved')

Searchable as RT46987$

p5pRT commented 17 years ago

From perl-diddler@tlinx.org

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.

#!/usr/bin/perl -w #use strict; # can optionally enable to show no "unstrict" constructs

## ## this prog demonstrates 3 related problems and a 4th example ## that may also be a problem; (all 4\, likely same cause) ## See descriptive text below after __END__ ##

{ package F;   our $count=-1;   sub boom { ++$count; $count==0 ? "two\n"​: $count==1 ?"one\n"​:"unprint\n";} } { package KA; our @​ISA = qw(F);   ## PROBLEM #1 'can' works even when 'boom' can't be called   ## PROBLEM #3b ( -- call to boom fails 2nd time through)   ## called as valid method   sub innocent{ if ($_[0]->can("boom")) {$_[0]->boom; }} #ln 18   #   sub laytrap {   {   my @​dummy=(\&boom); #ln 22   # (see comments below about 4th "concern")   # my $boom_defined=$dummy[0]; #ln 24   # print "boom defined = " . defined $boom_defined; #ln 25   # print "; boom exists = " . exists $boom_defined; #ln 26   # print "\n"; #ln 27   } "zero​:trap laid\n"   } } package main;   my $o = bless []\,"KA";

  ## These two calls (boom & innocent work...   print $o->boom; print $o->innocent;

  ## lay trap to break boom & innocent   print $o->laytrap;

  ## Now same two calls\, boom & innocent\, will fail​:   ## PROBLEM #2 -- can no longer call parent method 'boom'   ## (using eval to catch error)   eval {if ($o->can("boom")) {print $o->boom}}; #ln 43   $@​ && print "$@​";

  ## PROBLEM #3 - within 'innocent'\, call to 'boom' fails   ## this call terminates program (fatal Undefined error)   print $o->innocent;

__END__

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.

The 4th "problem is the commented-out section above numbered lines "24-26" (in comments). _*If*_ you can autovivify functions or methods\, then "exists()" should work with function references. Instead\, if you uncomment lines 24-27\, you will get an error​: "exists argument is not a HASH or ARRAY element at ./pbug1 line 26."

On the other hand\, if you allow "exists" to work with coderefs\, why not "simple vars"? I.e.​: $a=\$b\, then defined($a)=true\, but exists($a) would be 'false'\, meaning no space had been allocated to value "$b" (is undefined).

Sorry to bundle "4" problems together\, but they appeared to be related. If you want me to created another bug for #4 (it is the most different from the other 4)\, lemme know.


Flags​:   category=core   severity=high


Site configuration information for perl v5.8.8​:

Configured by rurban at Sun Jul 8 19​:08​:44 GMT 2007.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration​:   Platform​:   osname=cygwin\, osvers=1.5.24(0.15642)\, archname=cygwin-thread-multi-64int   uname='cygwin_nt-5.1 reini 1.5.24(0.15642) 2007-01-31 10​:57 i686 cygwin '   config_args='-de -Dmksymlinks -Duse64bitint -Dusethreads -Uusemymalloc -Doptimize=-O3 -Dman3ext=3pm -Dusesitecustomize -Dusedevel'   hint=recommended\, useposix=true\, d_sigaction=define   usethreads=define use5005threads=undef useithreads=define usemultiplicity=define   useperlio=define d_sfio=undef uselargefiles=define usesocks=undef   use64bitint=define use64bitall=undef uselongdouble=undef   usemymalloc=n\, bincompat5005=undef   Compiler​:   cc='gcc'\, ccflags ='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing -pipe -Wdeclaration-after-statement'\,   optimize='-O3'\,   cppflags='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing -pipe -Wdeclaration-after-statement'   ccversion=''\, gccversion='3.4.4 (cygming special\, gdc 0.12\, using dmd 0.125)'\, gccosandvers=''   intsize=4\, longsize=4\, ptrsize=4\, doublesize=8\, byteorder=12345678   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=12   ivtype='long long'\, ivsize=8\, nvtype='double'\, nvsize=8\, Off_t='off_t'\, lseeksize=8   alignbytes=8\, prototype=define   Linker and Libraries​:   ld='ld2'\, ldflags =' -s -L/usr/local/lib'   libpth=/usr/local/lib /usr/lib /lib   libs=-lgdbm -ldb -ldl -lcrypt -lgdbm_compat   perllibs=-ldl -lcrypt -lgdbm_compat   libc=/usr/lib/libc.a\, so=dll\, useshrplib=true\, libperl=libperl.a   gnulibc_version=''   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=dll\, d_dlsymun=undef\, ccdlflags=' -s'   cccdlflags=' '\, lddlflags=' -s -L/usr/local/lib'

Locally applied patches​:   CYG01 - hints.cygwin.sh ldflags -s   CYG02 - lib-ExtUtils-Embed insensitive against leading \\s   CYG03 - lib-Test-Harness-Straps $ENV{PERL5LIB} = ''   CYG04 - major.version.cygwin.sh cygperl-5_8.dll and not cygperl-5_8_x.dll   CYG05 - add Win32CORE to core   CYG07 - File-Spec-Cygwin-TMPDIR.patch   Bug#38628 - allow legacy Cwd->cwd()   Bug#40103 - File-Spec-case_tolerant.patch from 5.9.5


@​INC for perl v5.8.8​:   /usr/lib/perl5/5.8/cygwin   /usr/lib/perl5/5.8   /usr/lib/perl5/site_perl/5.8/cygwin   /usr/lib/perl5/site_perl/5.8   /usr/lib/perl5/site_perl/5.8   /usr/lib/perl5/vendor_perl/5.8/cygwin   /usr/lib/perl5/vendor_perl/5.8   /usr/lib/perl5/vendor_perl/5.8   .


Environment for perl v5.8.8​:   CYGWIN=notitle glob​:ignorecase export   HOME=/home/law   LANG (unset)   LANGUAGE (unset)   LD_LIBRARY_PATH (unset)   LOGDIR (unset)   PATH=.​:/sbin​:/usr/sbin​:/home/law/scripts​:/home/law/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/X11R6/bin​:/usr/bin​:/usr/lib​:/WINDOWS/system32​:/WINDOWS​:/WINDOWS/System32/Wbem​:/Prog/XP-Support Tools​:/Prog/sysinternals​:/Prog/Codeplay​:/Prog/Common Files/GTK/2.0/bin​:/Prog/Microsoft Visual Studio/Tools​:/usr/lib/lapack​:/c/Prog/Sysinternals/cmd   PERL_BADLANG (unset)   SHELL=C​:/bin/bash.exe

p5pRT commented 17 years ago

From @demerphq

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.

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.

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. 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.

With this modification I get the following output

two one zero​:trap laid unprint unprint

HTH\, Yves

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

p5pRT commented 17 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 17 years ago

From perl-diddler@tlinx.org

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?

  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.   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.

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.

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.

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".

  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');

  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. 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.

p5pRT commented 17 years ago

From @gbarr

On Oct 29\, 2007\, at 6​:13 PM\, Linda W wrote​:

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.

The OO lookup is working as it is supposed to. You created a
subroutine stub by using \&foo\, and stubs control the OO method
lookup in perl.

Graham.

p5pRT commented 17 years ago

From @demerphq

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/"

p5pRT commented 17 years ago

From perl-diddler@tlinx.org

This is probably too long a response\, but tried to answer all of the points brought up. Sigh. Focus on forests not trees?

demerphq wrote​:

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.


  Your explanation is based in Perl's internals. A bug in Perl's internals implementation is not supporting evidence for why documented OO calling functionality should be broken.

  It isn't the "reference" that is causing the problem -- though you are focusing on it as such because you are focusing on compile time. OO-method calling is *dynamic*. What is the right thing to do when the call is made?

  It is *only* at execution time that this "situation" can be resolved. It is at execution time\, that Perl knows whether or not \&boom is defined locally. At execution time\, I assert that Perl should look through Parent methods for a valid method\, and give priority to a defined parental method OVER DYING of a FATAL ERROR saying "the "method' is not defined".

  A second problem is that the UNIVERSAL "can()" method is broken as well. According to OO-Perl(Conway)\, "can only returnes true if an object or class can call the method requested". If the local method is "undefined" (as is stated in the error message)\, then "can()" cannot return a reference to that function -- since that function method is NOT legally callable.

    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.


  I was not trying to take a reference to the parent's subroutine. I am taking a reference to a routine who's location I do not know. I wanted to see if the reference returned "NULL" (or was undefined)\, or if the reference was 'valid'. I wasn't "blindly" expecting the reference to work. I wanted to see some indication that it wasn't defined\, so I wouldn't call it.   The problem is that Perl isn't behaving as defined for OO-calls.   Instead you go off justifying the bad-behavior based on Perl's internals. I understand that the perl internals won't return null or undef as a "value" when checking the result of \&undefined_routine. I understand that currently\, Perl blindly calls a "reference-created" stub. I'm saying that under OO rules\, it should not. Nor should "can" return "true" for methods that are "undefined".

  Justifying the current behavior based on Perl's internals doesn't mean it isn't a bug.

  While you said​: "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." -- based on how Perl is internally implemented\, you have to realize\, that the converse can be said of you​:

  The fact that you claim non-OO behavior is "desirable" because it is compatible with non-OO hash autovivification\, is not justifying the bug\, but may be -- moroe of a reflection of your (mis)understanding of how OO calls are to give *priority* to parent methods OVER throwing a "not found" error.

  I may not be an expert in Perl internals\, but the domain of correct OO behavior supersedes incorrect function based on language quirks due to implementation.

  I do not disagree (I agree) that if the call was "funkymethod($self)" throwing the error is desired behavior. I'm saying that Perl has to be smart enough to know the difference between "funkymethod($self) and "$self->funkymethod"\, and follow the OO method of searching parent methods *before* it throws an error for a non-existent\, local method.

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.

  A subroutine stub != a method call. The subroutine call wouldn't do OO lookups. \&func\, shouldn't take precedence in an OO call. If I had written "\&$self->method"\, then I _might_ agree the local symbol should be given preference -- but \&func isn't a valid way (as many have emphasized to me) to access a method name\, so it should not be used as a reason for "$self->method"\, an OO call\, to use such a "non-OO" reference to 'override' a valid parent method.

in the symbol table. Perl has to assume


  At execution time\, if the local symbol is "undefined"\, then it should look for a valid\, defined symbol. If I had defined the local function\, then YES\, I would expect Perl to override it -- but the function isn't *FULLY* defined (the body is missing). It's a "stub". Can you give 1 way in which calling an empty stub is preferable to looking through the parent classes first (that is not based in perl internals or how hard it is to get *correct*).

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.


  This is where we differ. I claim method calls look for methods. You are stuck in Perl's internals talking about 'entries'. OO-parlance doesn't talk about implementation-specific things like 'entries'.

You created one\,


  I created a non-existent forward-function reference -- not a valid method. "\&foo" is not an "OO" supported way of referencing or creating a "method".

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.


  Autovivification vivifies *function* *stubs*\, not OO-methods. AutoV. is a perl construct\, not an OO construct. In a compiler\, the bogus reference would fail at compile time as the referenced "local function" would not exist. In perl\, because of dynamic binding\, the final check for existence isn't done until execution time at the point the call is made. When the call is made\, OO->method should give OO-method lookup preference over perl's implementation specific _function_ autovivification OVER a *non-existent* function reference created by a non-OO reference. Certainly can we agree that \&foo is not a supported OO way of accessing methods? OO gets away from implementation specific details and using "addressof" type operators.

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.


  If Perl had only 1 call mechanism\, or if \&func was a supported\, or proper "OO" way to access methods\, I would agree\, but it wasn't. I'm saying that \&func isn't "OO" and that "OO" shouldn't give preference to "Throwing a Fatal Error"\, over doing the parent method search.

  Are you saying\, at execution time\, that when I have "$s->method" perl has no idea that this is an OO call that is *different* from "func($s)"? I had several OO-conversant people emphasize that even though methods and functions were *similar*\, they were not the same and should not be treated as such. If I (or you) agree with that -- then it makes sense that "func($s)" is a normal function call and "$s->method" is used for OO calls\, you can have it both ways.

  As for perl "doing what I am telling it to do" -- that's from your "internal" based perspective -- it is not the perspective of an OO implementation. From the OO perspective -- I would expect that \&undef_func would NOT override OO base-class searching because it is not an OO construct. I understand why you believe it the same from an internal\, standpoint\, but I don't feel internal implementation should be the "decider" of what is "desired" or what is correct from an OO standpoint\, since OO was defined before perl ever existed.

    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.


  Sorry\, I don't accept "wrong" on faith. I've always to know why. In this case\, "why" is because the internally-focus implementation produces incorrect behavior when viewed from an OO perspective.

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.


  I should not have to be a perl-internals expert to write in OO. If one has experience in OO\, one might have some pre-existing ideas. Such might be more so if one read a generally- -accepted-as-good\, OO-perl book. Can you point to an OO reference where it says that "Inherited-methods first search for undefined function stubs in an local-entry table"?

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.


  As I tried to explain multiple times -- the stubs *were* filled in. The program had NO CLASSES -- all functions started out as "local". Slowly\, conceptually-functional areas were broken apart into more manageable packages/classes. As long as all the calls were in the same "Package" (or class)\, it worked. At some point\, some of the "referenced" functions were moved from where the 'jump table' was used (as called from a Tk-keyboard-event handler).

The fact that you did so by a rather unusual mechanism is annoying I agree but is not wrong.


  I excel in fitting parts together in novel ways. :^)

Second\, you cant generally rely on references to subroutines\,


  See above.

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.


  Yes...and I see your example\, but the *very* str8forward translation from reference to named in doing something like   $self->"method"(params); Obviously wasn't going to work...​:-)   In fact\, the difference between "ref-based calling" and 'name-based' calling is\, unfortunately one of the problems with most of the OO examples I find. They all seem to use examples where "use strict;" is not used (something I tend to always use)\, and end up with examples like "$self->can(foo)" where it isn't immediately obvious that 'foo' is effectively treated as a string.

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.


  Well\, it really was "out of control" considering I was going from a complete non-OO case to an OO case in order to make it more easily extensible. But in testing -- if you want to find bugs\, you can't just do the 'controlled' testing\, but must also do the things that\, as a developer\, you know to steer around because you aren't sure\, based on implementation\, whether or not it will work. Most programmers just find the things that work and stick with them. If you want to find errors\, you have to do the things you wouldn't normally do or think of (!try that in the morning before coffee!).

    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.


  Yes -- I had red-flags -- but before I posted the first bit of code\, I'd gone through tons of variations -- some of which I didn't expect to work\, but\, since the things I expected to work\, were not\, I was trying things that I didn't expect to work\, but hoped would generate information to point the direction.

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.


  Yes...like I wouldn't have hit on "can" not working.   You may claim that "can" not working\, or that calling local functions\, KNOWN to be UNDEFINED\, should take precedence over searching base classes for matches\, are not bugs. But I disagree. Maybe you can get verification from Damian Conway? Doesn't he work on perl now and then? Can he verify that in an Object Oriented framework\, it is desirable to to give call-lookup precedence to a local\, undefined function over valid parent methods and that is desired behavior that "can()" return true for "function stubs" which are not callable methods?

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.


  If someone only wants their code to work and doesn't desire an understanding of "why" something is broken\, I'm sure they won't argue with someone giving them an a workaround instead of an answer. Eventually I got the help I needed regarding the example you were looking for and added in the cases I was concerned with. The resulting code was about 70 lines (or about 20 w/o debug statements showing the error at runtime).

  Sorry\, but I'd encountered too many different ways for this type of code to fail in too many variations to just accept a workaround. I wanted to know what was incorrect​: my understanding of OO\, a "massive braino disruption"\, misreading the various OO-perl examples and references\, or an unexpected "bug" ("feature") that threw off how I expected things to work vs. how they actually did.

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".


  I believe you are using a perl-implementation based reason as justification for the behavior. I don't agree that in an OO-implementation\, precedence should be given to a NON-OO reference (you agree it's not advisable to do in OO). In fact\, I don't know of any OO implementations that depend on method addresses between classes -- IT BREAKS the OO paradigm. But agreeing that "\&func" is not OO\, allows that the OO-specific call method should not rely on functions defined that way. I also do not agree that the "can()" function should be returning "true" when a valid _method_ is not available (and only a function stub is).

  Current implementation aside\, do you really believe the current implementation ("can" unreliable\, and local-undef-funcs supersede parent method calls) serves *any* valid or reasonable purpose. Can you put the current implementation aside and think or converse with OO experts (not other perl-internal experts). About the functionality as is and as suggested from a "functional" (within an Object Oriented Context) point of view?

p5pRT commented 17 years ago

From chris@prather.org

On Oct 29\, 2007\, at 9​:37 p\, Linda W wrote​:

A second problem is that the UNIVERSAL "can()" method is broken as well. According to OO-Perl(Conway)\, "can only returnes true if an object or class can call the method requested". If the local method is "undefined" (as is stated in the error message)\, then "can()" cannot return a reference to that function -- since that function
method is NOT legally callable.

This actually is documented behavior​:

can cannot know whether an object will be able to provide a method through AUTOLOAD\, so a return value of undef does not necessarily mean the object will not be able to handle the method call. To get around this some module authors use a forward declaration (see perlsub) for methods they will handle via AUTOLOAD. For such 'dummy' subs\, can will still return a code reference\, which\, when called\, will fall through to the AUTOLOAD. If no suitable AUTOLOAD is provided\, calling the coderef will cause an error.

from http​://search.cpan.org/~nwclark/perl-5.8.8/lib/UNIVERSAL.pm

-Chris

p5pRT commented 17 years ago

From chromatic@wgz.org

On Monday 29 October 2007 19​:37​:10 Linda W wrote​:

I claim method calls look for methods.  You are stuck in Perl's internals talking about 'entries'.

Objection​: Perl 5 makes no distinction in storage between methods and subs.
Method calls in Perl 5 do not look for methods. If you're lucky (or disciplined)\, Perl 5 will find methods. If you're unlucky (or undisciplined)\, Perl 5 will find subs.

Having subs into packages which you expect to contain only subs-acting-as-methods will lead to surprising behavior now and then\, as in this case.

I suppose that this could be a bug if you look at it a certain way\, but distinguishing between methods and subs would be a very big change for Perl 5.

-- c

p5pRT commented 17 years ago

From @samv

Linda W wrote​:

Your explanation is based in Perl's internals\.  A bug in

Perl's internals implementation is not supporting evidence for why documented OO calling functionality should be broken.

What you are referring to as the "internals" is actually well documented interface. The Symbol table\, much as some people like to call that internals\, is every much a part of the language as any other part. It even has its own sigil. Taking a reference to a hash slot\, for instance\, will "vivify" that hash slot. This is defined interface\, though it is partially motivated by the pragmatic concern to build an interface that matches the implementation. The same auto-vivification is happening here.

Current implementation aside\, do you really believe the current

implementation ("can" unreliable\, and local-undef-funcs supersede parent method calls) serves *any* valid or reasonable purpose. Can you put the current implementation aside and think or converse with OO experts (not other perl-internal experts). About the functionality as is and as suggested from a "functional" (within an Object Oriented Context) point of view?

I think as someone who makes most people's eyes glaze over whenever I talk about schemas and metamodels\, that I qualify as an OO expert. So\, here we are\, let's talk.

I've scanned over a couple of your e-mails\, and I think that you have a few valid points. Not that my opinion is particularly weighty\, not being a porter and all.

I for one agree that the default ->can() should only return true if there is a method that is callable. Instead of just looking for the CODE slot in the Glob with "exists"\, it should check "defined". Modules that expect ->can() to work on a more "exists"-like check\, and fudge the rest with AUTOLOAD /should/ be defining their own ->can(). I have no idea how many modules make use of this current behaviour.

I think the thing to do would be to knock up a patch to UNIVERSAL​::can and see how much of CPAN that change breaks. You can release this onto CPAN so that you can have a dependency that patches the running Perl to behave as you expect. See the existing UNIVERSAL​::can and UNIVERSAL​::isa distributions\, you can release it as something else that just assigns to *UNIVERSAL​::can. If you observe that not much breaks\, then it can be considered for inclusion. "All's fair if you pre-declare" they say\, so this might need a 'use feature' or equivalent to change this behaviour.

As far as methods vs functions goes\, well that's a slightly more daring change. Obviously it's in the Perl 6 definition\, which means that it's not completely out of the question for a later 5.x release. It's just very hard to specify how the language could change to cater for it. For instance\, if the current "CODE" glob slot was extended to allow "METHOD" and "FUNCTION"\, backwards compatibility could be maintained\, to some degree at least. But then you've also got the question of multimethods and methods that have particular type signatures - again\, calling for a prototype on CPAN first before anything is considered for being a language change.

Anyway\, in summary\, a prototype is worth a thousand flamewars\, so I'd suggest that you consider what can be implemented\, try to do so and come back with your results.

You may be interested in collaborating with Gerard Goosen\, as he is attempting instead of keeping Perl compatible with CPAN to port the best parts of CPAN with Perl\, freeing the language to evolve more freely. Perhaps he will be willing to entertain such a change in Kurila Perl.

Good luck\, Sam.

p5pRT commented 17 years ago

From @demerphq

On 10/30/07\, Sam Vilain \sam@​vilain\.net wrote​:

I for one agree that the default ->can() should only return true if there is a method that is callable. Instead of just looking for the CODE slot in the Glob with "exists"\, it should check "defined". Modules that expect ->can() to work on a more "exists"-like check\, and fudge the rest with AUTOLOAD /should/ be defining their own ->can(). I have no idea how many modules make use of this current behaviour.

Except that things work just fine if they are using autoload without needing to overload can.

As far as methods vs functions goes\, well that's a slightly more daring change. Obviously it's in the Perl 6 definition\, which means that it's not completely out of the question for a later 5.x release. It's just very hard to specify how the language could change to cater for it. For instance\, if the current "CODE" glob slot was extended to allow "METHOD" and "FUNCTION"\, backwards compatibility could be maintained\, to some degree at least. But then you've also got the question of multimethods and methods that have particular type signatures - again\, calling for a prototype on CPAN first before anything is considered for being a language change.

Its not only an issue of internals\, its also an issue of syntax. How would we denote these methods? How would they impact on back-compat? Would it just make things more complex for little gain by having the OO mechanism work with CODE *and* with METHOD? After all the existing code still has to work.

Personally I don't see the need\, unless we are going to make "first class" objects part of the language\, and I don't see that as being particularly feasible. Basically its just an issue that Perls OO is a pretty loose framework for associating data structures with the methods that operate on them with a few token gestures towards inheritance and overloading. If you expect perls OO to work the way it works in a static language with first class objects then you will find yourself surprised on occasion. OTOH If you ignore how other languages do OO then Perls OO is just fine.

Cheers\, yves

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

p5pRT commented 17 years ago

From @demerphq

On 10/30/07\, Linda W \perl\-diddler@​tlinx\.org wrote​:

This is probably too long a response\, but tried to answer all of the points brought up. Sigh. Focus on forests not trees?

demerphq wrote​:

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. --- Your explanation is based in Perl's internals. A bug in Perl's internals implementation is not supporting evidence for why documented OO calling functionality should be broken.

Its not a bug. Perl behaving the way you dont expect is not a bug. Perl behaving contrary to the way its documented to work is a bug. Perl in this case is behaving exactly as it was designed to work. Ergo its not a bug.

 It isn't the "reference" that is causing the problem \-\- though

you are focusing on it as such because you are focusing on compile time. OO-method calling is *dynamic*. What is the right thing to do when the call is made?

Er\, no. Im not. I dont understand how you come to this conclusion.

 It is \*only\* at execution time that this "situation" can be resolved\.

It is at execution time\, that Perl knows whether or not \&boom is defined locally. At execution time\, I assert that Perl should look through Parent methods for a valid method\, and give priority to a defined parental method OVER DYING of a FATAL ERROR saying "the "method' is not defined".

No\, it shouldnt. Because there are no 'valid methods' in perl. There are just entries in the symbol table. Its that simple.

 A second problem is that the UNIVERSAL "can\(\)" method is broken

as well. According to OO-Perl(Conway)\, "can only returnes true if an object or class can call the method requested". If the local method is "undefined" (as is stated in the error message)\, then "can()" cannot return a reference to that function -- since that function method is NOT legally callable.

Yes\, this is a consequence of dealing with a dynamic language. If you dont like it use a different language. Conway glossed over some of the stickier details in that quote\, probably because he didnt want to confuse things\, but Perl has to deal with AUTOLOAD and other dynamic issues.

    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. ---- I was not trying to take a reference to the parent's subroutine.

Well thats sure what your code and your original comments made it look like.

I am taking a reference to a routine who's location I do not know. I wanted to see if the reference returned "NULL" (or was undefined)\, or if the reference was 'valid'. I wasn't "blindly" expecting the reference to work. I wanted to see some indication that it wasn't defined\, so I wouldn't call it.

So\, you decided that by taking a reference to a subroutine it must return undef if that subroutine wasnt defined. But thats not how things work.

And you know ill just comment here​: You seem to really like using non-perl terminology in the context of Perl discussion\, and you don't seem to listen when people tell you not to and correct you. This just makes it hard to help you and indicates that you have gaps in your perl foundation knowledge which I think just add up to you thinking things should work in ways that they just don't.

    The problem is that Perl isn't behaving as defined for OO\-calls\.

How many times do people have to tell you that it IS behaving as defined before you will believe them and consider that it is your understanding that is flawed and not Perl's behaviour?

    Instead you go off justifying the bad\-behavior based on Perl's

internals.

Umm. No. I merely explain how Perl works. You can try to rationalize the disconnect between your flawed mental model and Perls actual behaviour all you wish but its not going to get you anywhere.

I understand that the perl internals won't return null or undef as a "value" when checking the result of \&undefined_routine. I understand that currently\, Perl blindly calls a "reference-created" stub. I'm saying that under OO rules\, it should not.

Whose OO rules? Yours? C++'es? Java's? Smalltalks? Pythons? Whichever rules you are speaking of aren't Perl's. There are no apriori OO rules. They are defined in a particular context. There may be general conventions that a dispatch mechanism is expected to abide by in order to be considered to be OO by the general programming public but the details are entirely within the remit of the language designer.

Nor should "can" return "true" for methods that are "undefined".

Says you. Graham bar says otherwise. Guess which one most people will listen to?

    Justifying the current behavior based on Perl's internals doesn't

mean it isn't a bug.

Well as other people have pointed out it is intentional\, and documented behaviour\, so its neither justified by Perl's internals nor is it a bug.

    While you said​: "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." -- based on how Perl is internally implemented\, you have to realize\, that the converse can be said of you​:

    The fact that you claim non\-OO behavior is "desirable" because it is

compatible with non-OO hash autovivification\, is not justifying the bug\, but may be -- moroe of a reflection of your (mis)understanding of how OO calls are to give *priority* to parent methods OVER throwing a "not found" error.

No. Wrong. That error is there for a reason. The reason being that Perl allows methods to be created on the fly. If Perl has been told that a method will be supplied later and the method is not suppled later the ONLY sane behaviour is to die with an error. Maybe the autoload routine is broken in some way. Perl cant know whats wrong\, all it knows is that something *is* wrong. Under such a scenario passing through to a parent method would be wrong\, as it may be that the parent method will do something inappropriate and maybe even dangerous.

    I may not be an expert in Perl internals\, but the domain of correct

OO behavior supersedes incorrect function based on language quirks due to implementation.

No sorry. Thats just wrong. As i said earlier\, there are only a few behaviours that are generally considered necessary for a dispatch mechanism to be considered to be OO. The details are necessarily left up to the language designer.

    I do not disagree \(I agree\) that if the call was "funkymethod\($self\)"

throwing the error is desired behavior. I'm saying that Perl has to be smart enough to know the difference between "funkymethod($self) and "$self->funkymethod"\, and follow the OO method of searching parent methods *before* it throws an error for a non-existent\, local method.

It wasnt non-existent. You created it. Perl has no way to know that you did it accidentally and didnt mean to do it.

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.

A subroutine stub != a method call. The subroutine call wouldn't do OO lookups. \&func\, shouldn't take precedence in an OO call. If I had written "\&$self->method"\, then I _might_ agree the local symbol should be given preference -- but \&func isn't a valid way (as many have emphasized to me) to access a method name\, so it should not be used as a reason for "$self->method"\, an OO call\, to use such a "non-OO" reference to 'override' a valid parent method.

Look\, Perl doesn't work the way you think it does or should. Either get used to it or don't use it. But repeating over and over incorrect assumptions is going to get you nowhere.

in the symbol table. Perl has to assume ---- At execution time\, if the local symbol is "undefined"\, then it should look for a valid\, defined symbol. If I had defined the local function\, then YES\, I would expect Perl to override it -- but the function isn't *FULLY* defined (the body is missing). It's a "stub". Can you give 1 way in which calling an empty stub is preferable to looking through the parent classes first (that is not based in perl internals or how hard it is to get *correct*).

AUTOLOAD.

The assumption is that if there is a subroutine stub its expected to be filled in later by autoload. If autoload doesnt do so then its an error in the code. Doing anything other than throwing an error would not make sense.

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. ---- This is where we differ. I claim method calls look for methods. You are stuck in Perl's internals talking about 'entries'. OO-parlance doesn't talk about implementation-specific things like 'entries'.

You are stuck in insisting that there is some ideal form of OO that all languages must comply with\, it isnt so\, has never been so and never will be so.

You created one\, --- I created a non-existent forward-function reference -- not a valid method. "\&foo" is not an "OO" supported way of referencing or creating a "method".

Argh. There is no way for perl to know if its a valid method or not. There is no difference between methods and functions in perl. Its that simple.

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. --- Autovivification vivifies *function* *stubs*\, not OO-methods. AutoV. is a perl construct\, not an OO construct. In a compiler\, the bogus reference would fail at compile time as the referenced "local function" would not exist. In perl\, because of dynamic binding\, the final check for existence isn't done until execution time at the point the call is made. When the call is made\, OO->method should give OO-method lookup preference over perl's implementation specific _function_ autovivification OVER a *non-existent* function reference created by a non-OO reference. Certainly can we agree that \&foo is not a supported OO way of accessing methods? OO gets away from implementation specific details and using "addressof" type operators.

No it shouldnt. It should assume that doing anything is inappropriate and should die\, and golly gee\, thats exactly what it does.

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. --- If Perl had only 1 call mechanism\, or if \&func was a supported\, or proper "OO" way to access methods\, I would agree\, but it wasn't. I'm saying that \&func isn't "OO" and that "OO" shouldn't give preference to "Throwing a Fatal Error"\, over doing the parent method search.

Sigh.

    Are you saying\, at execution time\, that when I have "$s\->method"

perl has no idea that this is an OO call that is *different* from "func($s)"?

Of course it knows the difference. One should use method dispatch and one should use direct dispatch. What im saying is that it doesnt know the difference between a sub or a method. The only difference is how it finds the sub. One does what is essentially a hash lookup in only the current package and the other does a recursive depth first search through the packages listed in @​ISA until it finds a package where the hash lookup returns something that looks like a subroutine.

I had several OO-conversant people emphasize that even though methods and functions were *similar*\, they were not the same and should not be treated as such. If I (or you) agree with that -- then it makes sense that "func($s)" is a normal function call and "$s->method" is used for OO calls\, you can have it both ways.

    As for perl "doing what I am telling it to do" \-\- that's from

your "internal" based perspective -- it is not the perspective of an OO implementation. From the OO perspective -- I would expect that \&undef_func would NOT override OO base-class searching because it is not an OO construct. I understand why you believe it the same from an internal\, standpoint\, but I don't feel internal implementation should be the "decider" of what is "desired" or what is correct from an OO standpoint\, since OO was defined before perl ever existed.

OO has changed over time. It doesnt have a definition as you seem to think\, it has a generally accepted set of requirements\, which as far as i know perl satisfies. Thats about it.

    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. --- Sorry\, I don't accept "wrong" on faith. I've always to know why. In this case\, "why" is because the internally-focus implementation produces incorrect behavior when viewed from an OO perspective.

No\, viewed from YOUR perspective of OO\, which appears to be heavily influenced by some other languages implementation. However that perspective of OO at the very least seems to not to take into account the consequences of Perl being a dynamic language and therefore is out of sync with the reality.

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. --- I should not have to be a perl-internals expert to write in OO. If one has experience in OO\, one might have some pre-existing ideas. Such might be more so if one read a generally- -accepted-as-good\, OO-perl book. Can you point to an OO reference where it says that "Inherited-methods first search for undefined function stubs in an local-entry table"?

Does everything have to be spelled out so explicity? The documentation explains exactly what Perl does\, and it explains things like AUTOLOAD and etc. If you put it together holistically these things are implicitly explained.

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. --- As I tried to explain multiple times -- the stubs *were* filled in. The program had NO CLASSES -- all functions started out as "local". Slowly\, conceptually-functional areas were broken apart into more manageable packages/classes. As long as all the calls were in the same "Package" (or class)\, it worked. At some point\, some of the "referenced" functions were moved from where the 'jump table' was used (as called from a Tk-keyboard-event handler).

It doesnt matter what your intentions were. It matters what the code did.

The fact that you did so by a rather unusual mechanism is annoying I agree but is not wrong. --- I excel in fitting parts together in novel ways. :^)

Second\, you cant generally rely on references to subroutines\, --- See above.

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. --- Yes...and I see your example\, but the *very* str8forward translation from reference to named in doing something like $self->"method"(params); Obviously wasn't going to work...​:-) In fact\, the difference between "ref-based calling" and 'name-based' calling is\, unfortunately one of the problems with most of the OO examples I find. They all seem to use examples where "use strict;" is not used (something I tend to always use)\, and end up with examples like "$self->can(foo)" where it isn't immediately obvious that 'foo' is effectively treated as a string.

If you see that please flag it as a documentation bug.

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. --- Well\, it really was "out of control" considering I was going from a complete non-OO case to an OO case in order to make it more easily extensible. But in testing -- if you want to find bugs\, you can't just do the 'controlled' testing\, but must also do the things that\, as a developer\, you know to steer around because you aren't sure\, based on implementation\, whether or not it will work. Most programmers just find the things that work and stick with them. If you want to find errors\, you have to do the things you wouldn't normally do or think of (!try that in the morning before coffee!).

    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. --- Yes -- I had red-flags -- but before I posted the first bit of code\, I'd gone through tons of variations -- some of which I didn't expect to work\, but\, since the things I expected to work\, were not\, I was trying things that I didn't expect to work\, but hoped would generate information to point the direction.

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. --- Yes...like I wouldn't have hit on "can" not working.

No\, you wouldnt have confused yourself into thinking that what can() did do was incorrect.

    You may claim that "can" not working\, or that calling local

functions\, KNOWN to be UNDEFINED\, should take precedence over searching base classes for matches\, are not bugs. But I disagree. Maybe you can get verification from Damian Conway? Doesn't he work on perl now and then? Can he verify that in an Object Oriented framework\, it is desirable to to give call-lookup precedence to a local\, undefined function over valid parent methods and that is desired behavior that "can()" return true for "function stubs" which are not callable methods?

Er\, im sure that if Damian Conway felt like getting involved in this disucssion he would.

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. --- If someone only wants their code to work and doesn't desire an understanding of "why" something is broken\, I'm sure they won't argue with someone giving them an a workaround instead of an answer. Eventually I got the help I needed regarding the example you were looking for and added in the cases I was concerned with. The resulting code was about 70 lines (or about 20 w/o debug statements showing the error at runtime).

    Sorry\, but I'd encountered too many different ways for this

type of code to fail in too many variations to just accept a workaround. I wanted to know what was incorrect​: my understanding of OO\, a "massive braino disruption"\, misreading the various OO-perl examples and references\, or an unexpected "bug" ("feature") that threw off how I expected things to work vs. how they actually did.

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". --- I believe you are using a perl-implementation based reason as justification for the behavior. I don't agree that in an OO-implementation\, precedence should be given to a NON-OO reference (you agree it's not advisable to do in OO). In fact\, I don't know of any OO implementations that depend on method addresses between classes -- IT BREAKS the OO paradigm. But agreeing that "\&func" is not OO\, allows that the OO-specific call method should not rely on functions defined that way. I also do not agree that the "can()" function should be returning "true" when a valid _method_ is not available (and only a function stub is).

    Current implementation aside\, do you really believe the current

implementation ("can" unreliable\, and local-undef-funcs supersede parent method calls) serves *any* valid or reasonable purpose.

Yes.

Can you put the current implementation aside and think or converse with OO experts (not other perl-internal experts). About the functionality as is and as suggested from a "functional" (within an Object Oriented Context) point of view?

If they are OO experts in non-dynamic languages then their opinion is irrelevent. If they are OO experts in dynamic languages then their opinion is probably much the same has been explained. They may quibble of various aspects of how Perl works\, but given the constraints various language design decisions impose on the functioning I would bet most open minded and well informed people would come to more or less similar conclusions.

If you are going to have lazy loading of subroutines (we do) and if you are going to have intrinsic type orthagonal to class (we do)\, if you are going to allow methods and subroutines to be redefined during normal program flow (we do) then there are various consequences. Its not unusual for people to find certain aspects of this to be unexpected and or undesirable\, but thats the situation we are in.

Most languages choose to sacrifice some of these features\, or to use alternate implementations to avoid these problems impacting OO. That fine\, but Perls heritage is of a language that started out without any support for OO and then added various 'neat' features over time. The end result is that we have a somewhat loose but highly flexible OO framework which occasionally surprises people who come from other backgrounds. There is not much we can do about that without designing a new language. (Which is being done in two separate projects currently).

BTW\, this is the last im going to contribute to this thread. Im sorry\, but i dont have time for it. Either get used to perls OO warts and all\, or switch languages. The alternative will just frustrate you and annoy the rest of us.

Yves

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

p5pRT commented 17 years ago

From @samv

demerphq wrote​:

On 10/30/07\, Sam Vilain \sam@​vilain\.net wrote​:

I for one agree that the default ->can() should only return true if there is a method that is callable. Instead of just looking for the CODE slot in the Glob with "exists"\, it should check "defined". Modules that expect ->can() to work on a more "exists"-like check\, and fudge the rest with AUTOLOAD /should/ be defining their own ->can(). I have no idea how many modules make use of this current behaviour.

Except that things work just fine if they are using autoload without needing to overload can.

Ok I think I now agree for overload classes this is a reasonable thing to do.

However for other classes if the CV is undef it's pretty much guaranteed that ->can() is going to return the wrong answer.

eg

perl -le '{   package X;sub n{bless{}\,X};\&y}   package main;my$x=X->n;   print $x->can("y")||0;   $x->y'

Perhaps this could have a warning for it?

As far as methods vs functions goes\, well that's a slightly more daring change. Obviously it's in the Perl 6 definition\, which means that it's not completely out of the question for a later 5.x release. It's just very hard to specify how the language could change to cater for it. For instance\, if the current "CODE" glob slot was extended to allow "METHOD" and "FUNCTION"\, backwards compatibility could be maintained\, to some degree at least. But then you've also got the question of multimethods and methods that have particular type signatures - again\, calling for a prototype on CPAN first before anything is considered for being a language change.

Its not only an issue of internals\, its also an issue of syntax. How would we denote these methods? How would they impact on back-compat? Would it just make things more complex for little gain by having the OO mechanism work with CODE *and* with METHOD? After all the existing code still has to work.

This is a similar problem to the one Class​::MultiMethods solves. The thing that lives in the CODE slot is a run-time dispatcher to METHOD or FUNCTION based on the context it finds itself in. Eminently prototypable :)

Basically its just an issue that Perls OO is a pretty loose framework for associating data structures with the methods that operate on them with a few token gestures towards inheritance and overloading. If you expect perls OO to work the way it works in a static language with first class objects then you will find yourself surprised on occasion.

Sure\, agreed.

OTOH If you ignore how other languages do OO then Perls OO is just fine.

I don't want to completely ignore Perl 6 :)

Sam

p5pRT commented 17 years ago

From perl-diddler@tlinx.org

This conversation is not going nearly as positively as I had hoped. :\~( Ignoring all the kicked up 'dust'\,

  I would prefer Perl\, continue to strive to be the (*usually*) user-friendly language that it is\, and try to do what the user might have really been intending before throwing a fatal error. Instead of "throwing an exception"\, when doing a 'method-syntax' type call\, look for parent methods before throwing an "Undefined" exception.

  In the same way Perl handles functions differently than global hashes and attempts "AUTOLOAD" before returning failure\, I'm proposing performing another "check" before giving up. If method-call syntax was used\, check parent classes for a possible match​:

if ( $function_referenced && !exists &$function_referenced ) {   # (this code is only called after AUTOLOAD has failed   # and Perl is about to throw "Fatal Undef" error)   #   If ($user_used_method_call && search_base_classes("method") == True) {   If ($warn_OO_override) {   warn "Warning​: Undefined-local-stub '$method' ignored";   }   call_base_method("parent"\, $self\, "method");   } }


  Unless someone is purposefully trying to die with a Fatal undefined error\, I don't see this behavior causing a compatibility problem\, as it is only called when the program would have terminated anyway.

Linda

p5pRT commented 17 years ago

From @druud62

Linda W schreef​:

 I would prefer Perl\, continue to strive to be the \(\*usually\*\)

user-friendly language that it is\, and try to do what the user might have really been intending before throwing a fatal error.

What do you think that "return \%data{@​keys}" means? It pretty much looks to me like the user wants to return a reference to a hash slice. To make it sort of work\, you could write it like I show below\, but that involves copying\, which might not be what the user wanted​:

  my %tmp;   @​tmp{@​keys} = @​data{@​keys};   return \%tmp;

-- Affijn\, Ruud

"Gewoon is een tijger."

p5pRT commented 17 years ago

From @jbenjore

On Thu\, Nov 01\, 2007 at 10​:08​:58PM +0100\, Dr.Ruud wrote​: } Linda W schreef​: } } > I would prefer Perl\, continue to strive to be the (*usually*) } > user-friendly language that it is\, and try to do what the user } > might have really been intending before throwing a fatal error. } } What do you think that "return \%data{@​keys}" means? It pretty much } looks to me like the user wants to return a reference to a hash slice. } To make it sort of work\, you could write it like I show below\, but that } involves copying\, which might not be what the user wanted​: } } my %tmp; } @​tmp{@​keys} = @​data{@​keys}; } return \%tmp;

To get what you want requires trickery. It's an array reference where the elements are aliased back to the values in %data.

return sub { \@​_ }->( @​data{@​keys } );

-- Josh

p5pRT commented 17 years ago

From perl-diddler@tlinx.org

Am closing this bug out\, as I can agree\, technically\, it isn't a bug from perl's technical\, and (IMO) non-standard override of a "valid method" (a fully defined method) with a "function stub" (an incomplete function or method definition). It's my intent to resubmit a variation of this as an RFE -- that should be backward compatible for "calling" ("can" working or not is another matter\, since\, if I understand protestations to the contrary\, it is already in use in legacy code that relies on its current (though questionable\, IMO) behavior.

p5pRT commented 17 years ago

perl-diddler@tlinx.org - Status changed from 'open' to 'resolved'