Perl / perl5

đŸȘ The Perl programming language
https://dev.perl.org/perl5/
Other
1.88k stars 530 forks source link

Try OO semantics before throwing fatal error #9101

Closed p5pRT closed 12 years ago

p5pRT commented 16 years ago

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

Searchable as RT47181$

p5pRT commented 16 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.

This is a suggestion to make perl "less surprising" for people who have been exposed to Object Oriented (OO) concepts outside of perl. Not that it is the "ultimate source"\, but _consistent_ with my view that there exist\, general OO concepts\, and that one of those has to do with a local "method" overriding a parent\, or base class method. Specifically\, quoting from Wikipedia's currently listed entry on "method overriding"​:

  "Method overriding\, in object oriented programming\, is a language   feature that allows a subclass to provide a __specific_   _implementation__ of a method that is already provided by one of its   superclasses. The _implementation_ in the subclass overrides   (replaces) the implementation in the superclass."

The underlines are mine -- since some believe that supplying an "undefined\, forwardly-declared function stub" qualifies\, in perl\, as a "specific implementation" that should replace the implementation in the superclass.

Perl has runtime features that can turn what may seem to be an undefined function stub\, and turn it into something useful via Perl's AUTOLOAD functionality that can catch\, undefined subroutines and load them at runtime.

However\, after AUTOLOAD has been attempted (in order to maintain consistency with past behavior)\, if the requested function is _still_ undefined and Perl is about to 'throw' a Fatal Undefined exception\, then as a last-ditch effort to do *something* that the user might have meant; if the user used "OO-syntax" instead of a normal looking function call\, then I am requesting that perl (as an enhancement to more closely align itself with some people's expectations of OO behavior) search the object's base classes to see if the method is defined in the parent. If so\, then call that parent\, AND (if warnings are turned on)\, issue a runtime warning\, about the local stub being ignored.

Since this change would only be applied before Perl would normally have died from a fatal error\, I can't see it affecting current programs -- only programs that would have died anyway. This way -- at runtime\, the user is given a warning about the local-stub\, and perl tries to do what the user likely intended (i.e. - the "\&method" was in the same package (and was local) to where "sub method{}" was defined\, but the two lines of code had become separated; the \&method was meant to refer to the parent's method\, but had become outdated/non-intended code due to the split. An example generating the Undef error​: package A;   sub method {'method'}; package B; @​ISA=qw(A);   sub setup_error{ $x=\&method;} package main; bless my $ref={}\,B; print $ref->method . "\n"; $ref->setup_error(); print $ref->method . "\n";

=== Instead of "Undefined subroutine &B​::method called..."\, Perl could look for and call "method" as defined in package A.


Flags​:   category=core   severity=low


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 16 years ago

From @JohnPeacock

Linda Walsh (via RT) wrote​:

Perl has runtime features that can turn what may seem to be an undefined function stub\, and turn it into something useful via Perl's AUTOLOAD functionality that can catch\, undefined subroutines and load them at runtime.

There's nothing wrong with Perl's OO design. It isn't going to change (except in so much as what Perl6 does). There is no point in opening this bug/enhancement request\, because you are [apparently] the only person who thinks the current behavior is a problem. Sorry to be harsh\, but you have been told repeatedly that the problem is your interpretation of how Perl's object design works. Perhaps you want the Java or C++ offices down the hall...

John

p5pRT commented 16 years ago

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

p5pRT commented 16 years ago

From @jbenjore

On Tue\, Nov 06\, 2007 at 06​:25​:51AM -0500\, John Peacock wrote​: } Linda Walsh (via RT) wrote​: } > Perl has runtime features that can turn what may seem to be an undefined } > function stub\, and turn it into something useful via Perl's AUTOLOAD } > functionality that can catch\, undefined subroutines and load them at } > runtime.
} } There's nothing wrong with Perl's OO design. It isn't going to change (except } in so much as what Perl6 does). There is no point in opening this } bug/enhancement request\, because you are [apparently] the only person who thinks } the current behavior is a problem. Sorry to be harsh\, but you have been told } repeatedly that the problem is your interpretation of how Perl's object design } works. Perhaps you want the Java or C++ offices down the hall...

Gosh\, I dunno. I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies. I've gotten the impression that the people responding to her are more out to brow-beat Linda than argue about anything technical.

I've supposed that the real reason several people continued a thread with her was that they were irritated at her tone.

PS​: having to write defined(&{ ...->can(...) }) in user code to ignore undefined bodies sucks.

-- Josh

p5pRT commented 16 years ago

From @nwc10

On Tue\, Nov 06\, 2007 at 06​:54​:13AM -0800\, Josh Jore wrote​:

On Tue\, Nov 06\, 2007 at 06​:25​:51AM -0500\, John Peacock wrote​: } Linda Walsh (via RT) wrote​: } > Perl has runtime features that can turn what may seem to be an undefined } > function stub\, and turn it into something useful via Perl's AUTOLOAD } > functionality that can catch\, undefined subroutines and load them at } > runtime.
} } There's nothing wrong with Perl's OO design. It isn't going to change (except } in so much as what Perl6 does). There is no point in opening this } bug/enhancement request\, because you are [apparently] the only person who thinks } the current behavior is a problem. Sorry to be harsh\, but you have been told } repeatedly that the problem is your interpretation of how Perl's object design } works. Perhaps you want the Java or C++ offices down the hall...

Gosh\, I dunno. I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies. I've gotten the impression that the people responding to her are more out to brow-beat Linda than argue about anything technical.

I wouldn't want it to skip over undefined bodies in the general case. If you write (the equivalent of)

  sub Foo​::bar;

then I'd expect it to try Foo​::AUTOLOAD\, and if that fails\, fail. Otherwise it might silently hide a bug in Foo's AUTOLOAD

Else why would you stub subroutine bar in package Foo.

But for the case of taking a reference to an undefined subroutine\, I can see why that might want to behave differently\, and (implied) internally be represented by something different and distinguishable from a stub.

As this is just for the case of methods\, I'm not sure what it really gains over making method calls by name (which has been around\, IIRC\, since 5.005)\, but it would introduce both implementation and conceptual complexity.

Nicholas Clark

p5pRT commented 16 years ago

From @jbenjore

On Tue\, Nov 06\, 2007 at 03​:07​:16PM +0000\, Nicholas Clark wrote​: } As this is just for the case of methods\, I'm not sure what it really gains } over making method calls by name (which has been around\, IIRC\, since 5.005)\, } but it would introduce both implementation and conceptual complexity.

It breaks method calls by names. That's the point. If I ask ->can() and get a function back\, I don't ever check that the function is defined. Mostly I assume it's defined. It never would have occurred to me that ->can and ->foo would find these ghostie little methods.

\&foo; say main->can( 'foo' ); # finds CODE=(0x...) say defined &{ main->can( 'foo' ) }; # false eval 'sub UNIVERSAL​::foo { }'; main->foo; # throws error

Did you just say that main->foo should work?

-- Josh

p5pRT commented 16 years ago

From @JohnPeacock

Josh Jore wrote​:

It breaks method calls by names. That's the point. If I ask ->can() and get a function back\, I don't ever check that the function is defined. Mostly I assume it's defined. It never would have occurred to me that ->can and ->foo would find these ghostie little methods.

\&foo;

What is the justification for the above line in real code? This is the real problem\, not anything to do with the rest of the example code you gave.

This is the piece of the puzzle that *many* people tried to get Ms. Walsh to understand - you can't just take references of possibly undefined function names and expect everything to Just Work(TM). It isn't a bug in Perl\, it is a "Carbon-base error".

John

p5pRT commented 16 years ago

From @jbenjore

On Tue\, Nov 06\, 2007 at 11​:00​:48AM -0500\, John Peacock wrote​:

Josh Jore wrote​:

It breaks method calls by names. That's the point. If I ask ->can() and get a function back\, I don't ever check that the function is defined. Mostly I assume it's defined. It never would have occurred to me that ->can and ->foo would find these ghostie little methods. \&foo;

What is the justification for the above line in real code? This is the real problem\, not anything to do with the rest of the example code you gave.

This is the piece of the puzzle that *many* people tried to get Ms. Walsh to understand - you can't just take references of possibly undefined function names and expect everything to Just Work(TM). It isn't a bug in Perl\, it is a "Carbon-base error".

Ok\, I don't think it's a user error. Taking references to functions that don't exist yet is a normal part of perl. Of course you can't call them directly. Sure. I just wouldn't expect the action at a distance to interfere with MRO.

-- Josh

p5pRT commented 16 years ago

From chromatic@wgz.org

On Tuesday 06 November 2007 07​:38​:32 Josh Jore wrote​:

If I ask ->can() and get a function back\, I don't ever check that the function is defined. Mostly I assume it's defined. It never would have occurred to me that ->can and ->foo would find these ghostie little methods.

\&foo; say main->can( 'foo' ); # finds CODE=(0x...) say defined &{ main->can( 'foo' ) }; # false eval 'sub UNIVERSAL​::foo { }'; main->foo; # throws error

Did you just say that main->foo should work?

If I recall correctly\, the stubs work the way they do so that code like this will work​:

  use Test​::More tests => 2;   use Test​::Exception;

  package Stubs;

  BEGIN { my $stub = \&foo }

  package main;

  my $foo = Stubs->can( 'foo' );

  throws_ok { $foo->() } qr/Undefined sub/\, 'Stub not callable';

  {   no strict 'refs';   *{ 'Stubs​::foo' } = sub { 2 }   }

  is( $foo->()\, 2\, 'stub callable after definition' );

... not that I expect that anyone ever gets can() correct\, but that's a different rant.

If you want a more methody system\, throw into Stubs​:

  sub new { bless {}\, shift }

... and then add​:

  my $s = Stubs->new();

  is( $s->$foo()\, 2\, 'stub callable as method after definition' );

I don't think the bug is in method resolution. I don't think the bug is in can(). I also don't think there's a good general heuristic that can support this behavior while distinguishing between accidentally taking a reference to an undefined invokable symbol that just happens to share a name with a method somewhere in a resolution hierarchy\, so I don't think there's a fix for this behavior if it happens not to be a bug in the invokable object.

If there *is* such a heuristic though\, maybe it's worth considering Linda's feature request.

-- c

p5pRT commented 16 years ago

From @JohnPeacock

chromatic wrote​:

I don't think the bug is in method resolution. I don't think the bug is in can(). I also don't think there's a good general heuristic that can support this behavior while distinguishing between accidentally taking a reference to an undefined invokable symbol that just happens to share a name with a method somewhere in a resolution hierarchy\, so I don't think there's a fix for this behavior if it happens not to be a bug in the invokable object.

There is this minor annoyance that Perl is a *dynamic* language\, so I can require or use modules _long_ after the reference has been taken\, so the lazy resolution won't happen until that method is actually called. At that point\, there is no way of knowing whether the inherited method should be called (or in fact which multiply-inherited method was intended).

How about the instance where I write a subclass\, deliberately break the inheritance for a method (say it is an expensive full-table database search) on the assumption that my code never uses that call\, and any other code making that call should die (or be forced to use eval to catch that behavior).

I'll do you one better - I don't think this is a bug. We could add a large warning not to take references to function names (without testing for definedness) if you expect OO inheritance to have any hope of working\, but it isn't something that can be "fixed"\, AFAICT and IMNSHO...

John

p5pRT commented 16 years ago

From @davidnicol

Here is how to refer to a subroutine reference by name without autovivving it.

$ perl -le 'sub x{8}; print *x{CODE}; print *y{CODE}; print \&x;\   print \&y; print *y{CODE}' CODE(0x1002f10c)

CODE(0x1002f10c) CODE(0x1002f0f4) CODE(0x1002f0f4)

$ perl LWALSHfix.pl method method

$ diff -u LWALSH.pl LWALSHfix.pl

Inline Patch ```diff --- LWALSH.pl 2007-11-06 16:52:48.000000000 -0600 +++ LWALSHfix.pl 2007-11-06 16:59:18.000000000 -0600 @@ -6,7 +6,7 @@ package B; @ISA=qw(A); - sub setup_error{ $x=\&method;} + sub setup_error{ $x=*method{CODE}; } package main; ```
p5pRT commented 16 years ago

From @jbenjore

On Tue\, Nov 06\, 2007 at 10​:10​:40AM -0800\, chromatic wrote​: } On Tuesday 06 November 2007 07​:38​:32 Josh Jore wrote​: } package Stubs; } } BEGIN { my $stub = \&foo }

Your demo behaves the same way if the block reads BEGIN { \&foo }. You took a copy of the reference but it didn't matter. Just having done the reference once is enough to install a method-killing stub.

} I don't think the bug is in method resolution. I don't think the bug is in } can(). I also don't think there's a good general heuristic that can support

I am picking of method resolution because I think can() is a client of method resolution. I am also picking on it because it's the part that would at runtime need to know that \&foo isn't a a stubbed function - it is a forward reference.

Right now I think stubs and forward references are merely root and xsubless. I suppose with a flag\, the forward references that are not also stubs could be detected and ignored during method resolution. If not a flag\, attaching a piece of magic. It is reasonable to attach new magic because I expect these types of references to rare. If they were common then a bit in flags could be stolen. There's a handful free for SVt_PVCV.

Or is it also important to throw the undefined exception if the forward reference still exists? Right now the reference remains in the symbol table even if the user-side was reaped immediately.

Mostly I just responded to this thread because I didn't like the tone of the "No! You're wrong!" messages from p5p-at-large to Linda.

-- Josh

p5pRT commented 16 years ago

From @ap

* Josh Jore \twists@​gmail\.com [2007-11-06 15​:55]​:

I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies.

MR responding to stubs was added for a reason. The only way to “fix” this behaviour without obliterating its original and fully intentional functionality is to skip stubs in absence of AUTOLOAD\, but respect them in its presence.

“You find a problem with a special case. You fix it by special- casing the special case. Now you have two problems.”

I've gotten the impression that the people responding to her are more out to brow-beat Linda than argue about anything technical.

Linda wants to check whether a sub exists. Doing so by taking a reference to it is wrong – doing that creates a stub by design.

The fact that this is causing method resolution to later fail is a red herring. Even if a special case was added to the special case in MR her code would *still* be creating extraneous stubs.

Perl already has a perfectly servicable way to do what she needs​: she can check the CODE slot in the relevant glob.

Why are we still having this discussion?

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

From ben@morrow.me.uk

Quoth twists@​gmail.com (Josh Jore)​:

Ok\, I don't think it's a user error. Taking references to functions that don't exist yet is a normal part of perl. Of course you can't call them directly. Sure. I just wouldn't expect the action at a distance to interfere with MRO.

Method dispatch has to honour these autoviv'd stubs\, as it's the only way to get ->can to work when AUTOLOAD does the work itself rather than installing a sub. Consider​:

  package Foo;

  use Carp;

  sub can {   $_[0] =~ /a/ and return \&{$_[0]};   }

  sub AUTOLOAD {   $AUTOLOAD =~ /a/ or croak "No such method '$AUTOLOAD'";   return $AUTOLOAD;   }

Perl can't re-attempt named dispatch if AUTOLOAD fails\, as there's no way to tell if the failure was because the method doesn't exist or for some other reason; and it can't look past the stub if there isn't an AUTOLOAD\, because it's documented that named dispatch is over before AUTOLOAD is even looked for. It would be very weird if adding an AUTOLOAD changed inheritance.

Ben

p5pRT commented 16 years ago

From @nwc10

On Tue\, Nov 06\, 2007 at 05​:49​:22PM -0800\, Josh Jore wrote​:

I am picking of method resolution because I think can() is a client of method resolution. I am also picking on it because it's the part that would at runtime need to know that \&foo isn't a a stubbed function - it is a forward reference.

I guess that's the key part. Right now\, to all intents and purposes\, \&foo; *is* a stubbed function. It's just a different way of writing sub foo;

Right now I think stubs and forward references are merely root and xsubless. I suppose with a flag\, the forward references that are not also stubs could be detected and ignored during method resolution. If not a flag\, attaching a piece of magic. It is reasonable to attach new magic because I expect these types of references to rare. If they were common then a bit in flags could be stolen. There's a handful free for SVt_PVCV.

Implementation wise I think that it would be better to do it with attached magic. The other way\, it becomes tricky to easily determine by symbol table introspection whether it's a stub or a not-a-stub. If the reference has magic (and hence knows its name\, in case it gets called) then nothing need ever get written into the symbol table (which I think would give behaviour consistent with desired intent)

Or is it also important to throw the undefined exception if the forward reference still exists? Right now the reference remains in the symbol table even if the user-side was reaped immediately.

I guess that that would be why I think implementing with magic would be better.

Mostly I just responded to this thread because I didn't like the tone of the "No! You're wrong!" messages from p5p-at-large to Linda.

The tone of "it's a really important bug that's been here since 1994 that no-one else has found" doesn't help one's cause. That has now gone\, which is good.

It could be changed. I'm more concerned as to whether language design wise it's a good idea - in itself it adds slight complexity to the language\, but couple it with the existing behaviour\, and having to explain the two\, and it all gets more complex.

It's rather like the thoughts on the proposal for each @​array\, then keys @​array and values @​array - values @​array serves no purpose\, but it's easier to put it in than to document that "it would serve no purpose and so it's not part of the language". It's the complexity of "pre 5.10/post 5.10" that I'm thinking of.

Nicholas Clark

p5pRT commented 16 years ago

From @ap

* Nicholas Clark \nick@&#8203;ccl4\.org [2007-11-07 19​:35]​:

It could be changed. I'm more concerned as to whether language design wise it's a good idea - in itself it adds slight complexity to the language\, but couple it with the existing behaviour\, and having to explain the two\, and it all gets more complex.

Cf. http​://blog.plover.com/prog/featurism.html

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

From gerard@tty.nl

Starting with a note about the previous discussion about OO and autovivication.

Claiming that the current behaviour is logical\, well documented\, and not a reflection of how the internals work is ludicrous; About the only thing you can say about it is that it is the way it works. And because Perl 5 is obsessed with backward compatibility (in a rather narrow technical way\, where compatible is being interpreted as a program having the same output)\, this won't change in Perl 5. (Strange actually this rigidity\, for a language with such a natural language background\, and claiming to be DWIM\, I guess 'I' currently stands for "somebody more then 10 years ago")

I find it disgraceful to see people hiding behind technical details and historical justification\, and not having the courage to say that it might be crazy\, error-prone\, etc\, but it is the way it currently works and we're stuck with it.

Getting rid of this backwards compatibility thing is the one of the primary reasons for Perl Kurila.

Back to the actual proposal\, I would say it would only make things worse\, by adding more complexity. To make the whole OO-method-resolution a lot more sane\, I would like to do​: - Skip the 'undef' subs (as already suggested). - Do not allow forward declarations. - Remove AUTOLOAD

The first two are pretty straightforward and easy to do without breaking anything serious. The last one will need some refactoring of stuff currently using AUTOLOAD.

-- Gerard Goossen TTY Internet Solutions

p5pRT commented 16 years ago

From @davidnicol

On Nov 7\, 2007 12​:29 PM\, Nicholas Clark \nick@&#8203;ccl4\.org wrote​:

Implementation wise I think that it would be better to do it with attached magic. The other way\, it becomes tricky to easily determine by symbol table introspection whether it's a stub or a not-a-stub. If the reference has magic (and hence knows its name\, in case it gets called) then nothing need ever get written into the symbol table (which I think would give behaviour consistent with desired intent)

one could create some pure-perl stuff (using overload\, i think -- maybe TIESCALAR would work\, not sure) so instead of writing

  $wfcr = \&method;

one could write

  $wfcr = WeakForwardCodeReference 'method';

after that\, $wfcr checks to see if *method{CODE} is defined yet every time its fetched\, and if/when that ever happens\, $wfcr upgrades itself to the real deal.

something like

package WeakForwardCodeReference; use overload '&{}' => sub {   my $r = $_[0];   *{$$r}{CODE} and return $_[0] = *{$$r}{CODE};   $r }; sub WeakForwardCodeReference($){   my $name = shift;   $name =~ /​::/ or $name = caller().'​::'.$name;   bless \$name }; sub import { *{caller().'​::WeakForwardCodeReference'} = \&WeakForwardCodeReference}; 1; =head1 synopsis

  use WeakForwardCodeReference;   # my $FCR = \&SomeMethod; \<--- this breaks OO method resolution!   my $FCR = WeakForwardCodeReference 'SomeMethod';

=head1 details

look at the source -- it's really short

=head1 license

your choice of GPL or AL\, and version of either

=cut

__END__

p5pRT commented 16 years ago

From @ap

* Gerard Goossen \gerard@&#8203;tty\.nl [2007-11-07 21​:15]​:

(Strange actually this rigidity\, for a language with such a natural language background\, and claiming to be DWIM\, I guess 'I' currently stands for "somebody more then 10 years ago")

Perl’s original culture is the sysadmin world. Does it surprise you that stability enjoys ultimate priority among its goals?

not having the courage to say that it might be crazy\, error-prone\, etc\, but it is the way it currently works and we're stuck with it.

For my part I did say “for better or for worse” regarding autovivification.

Method resolution respecting stubs was a hack put in to deal with AUTOLOAD limitations; the only way to fix the problem it causes is by hacking the hack. As I said\, “now you have two problems.”

To make the whole OO-method-resolution a lot more sane\,

Method resolution is a red herring. The issue at hand is stubs and forward references\, where Perl 5 does not preserve enough information at the time of stub creation/forward ref taking to be later be able to distinguish them.

I would like to do​: - Skip the 'undef' subs (as already suggested). - Do not allow forward declarations.

If you remove forward declarations it seems to me there is really no need to even have stubs at all.

- Remove AUTOLOAD

How are people supposed to write proxy objects without AUTOLOAD?

If classes were closed by default and Kurila acquires sane reflection facilities I guess you could use reflection to create methods as needed\, but with open classes that does not seem like an option to me. But then it’s no possible anymore to have a class whose instances proxy objects in different classes\, which is how things like Object​::Trampoline do their job.

You could create a mechanism by which code can be notified of changes to a class\, I guess; then proxies could modify themselves in response to modifications in their proxied classes\, and classes whose instances need to proxy instances of different classes could create new proxy classes at runtime. I suppose.

I’m not sure it would be possible to sanely compose proxies anymore though.

Also\, efficient is something else.

Have you already thought of this maybe? Do you possibly already have an approach in mind for how to address this?

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

From @jbenjore

On Wed\, Nov 07\, 2007 at 05​:43​:05PM +0000\, Ben Morrow wrote​: } } Quoth twists@​gmail.com (Josh Jore)​: } > } > Ok\, I don't think it's a user error. Taking references to functions } > that don't exist yet is a normal part of perl. Of course you can't } > call them directly. Sure. I just wouldn't expect the action at a } > distance to interfere with MRO. } } Method dispatch has to honour these autoviv'd stubs\, as it's the only } way to get ->can to work when AUTOLOAD does the work itself rather than } installing a sub. Consider​: } } package Foo; } } use Carp; } } sub can { } $_[0] =~ /a/ and return \&{$_[0]}; } } } } sub AUTOLOAD { } $AUTOLOAD =~ /a/ or croak "No such method '$AUTOLOAD'"; } return $AUTOLOAD; } }

Did you mean to write exploding code? (I assume you typo'd $_[1] as $_[0]). What's the point of leaving a trail of autovivified bombs in the symbol table?

  Foo->a;   Foo->can( 'a' );   Foo->a; # boom

I can't do either of these to ever make use of the returned reference.

  *{ Foo->can('a') } = sub { ... }   &{ Foo->can('a') } = sub { ... }

I don't see what you mean about "the only way to write ->can." This doesn't leave bombs.

  sub can {   my $method = $_[1];   $method =~ /a/ and return sub {   $AUTOLOAD = $method;   &AUTOLOAD;   };   }

So what was your point?

-- Josh

p5pRT commented 16 years ago

From @ap

* Josh Jore \twists@&#8203;gmail\.com [2007-11-08 07​:20]​:

What's the point of leaving a trail of autovivified bombs in the symbol table?

If he did that\, it would be pointless indeed. He doesn’t\, so it isn’t.

Foo->a; Foo->can( 'a' ); Foo->a; # boom

Really? Did you *try* it?

  $ perl -le'sub AUTOLOAD { warn } \&foo; main->foo'   Warning​: something's wrong at -e line 1.

Well look it there\, I guess that *didn’t* go boom.

In the presence of AUTOLOAD\, stubs invoke AUTOLOAD instead of blowing up. That is the entire reason for the back-and-forth over this issue.

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

@rgs - Status changed from 'open' to 'rejected'

p5pRT commented 16 years ago

From ben@morrow.me.uk

Quoth twists@​gmail.com (Josh Jore)​:

On Wed\, Nov 07\, 2007 at 05​:43​:05PM +0000\, Ben Morrow wrote​: } Quoth twists@​gmail.com (Josh Jore)​: } > } > Ok\, I don't think it's a user error. Taking references to functions } > that don't exist yet is a normal part of perl. Of course you can't } > call them directly. Sure. I just wouldn't expect the action at a } > distance to interfere with MRO. } } Method dispatch has to honour these autoviv'd stubs\, as it's the only } way to get ->can to work when AUTOLOAD does the work itself rather than } installing a sub. Consider​: } } package Foo; } } use Carp; } } sub can { } $_[0] =~ /a/ and return \&{$_[0]}; } } } } sub AUTOLOAD { } $AUTOLOAD =~ /a/ or croak "No such method '$AUTOLOAD'"; } return $AUTOLOAD; } }

Did you mean to write exploding code? (I assume you typo'd $_[1] as $_[0]).

(yes\, of course; sorry)

What's the point of leaving a trail of autovivified bombs in the symbol table?

Foo->a; Foo->can( 'a' ); Foo->a; # boom

I don't know what you mean by 'boom'. I get

  ~% perl -MFoo -le'print for Foo->a\, Foo->can("a")\, Foo->a'   Foo​::a   CODE(0x80a2900)   Foo​::a

as I would have expected.

I can't do either of these to ever make use of the returned reference.

*{ Foo->can('a') } = sub { ... } &{ Foo->can('a') } = sub { ... }

You can *call* them. Again​:

  ~% perl -MFoo -le'print Foo->can("a")->()'   Foo​::a

I don't see what you mean about "the only way to write ->can." This doesn't leave bombs.

sub can { my $method = $_[1]; $method =~ /a/ and return sub { $AUTOLOAD = $method; &AUTOLOAD; }; }

No\, but it doesn't do the right thing either. The coderef returned from can is *different* from the one that would have been called by the method​: the call stack is wrong. Worse\, it's different every time it's called​: you would end up with Foo->can('a') != Foo->can('a'). Besides\, you're constructing a whole nother sub to call\, and the point of having AUTOLOAD do the work is to avoid that.

All of that may or may not be fixable\, but simply returning a ref to a sub which doesn't exist yet is a simple\, clean way around the problem that currently works perfectly. Changing this would be a serious change in behaviour.

Ben

p5pRT commented 16 years ago

From gerard@tty.nl

On Thu\, Nov 08\, 2007 at 04​:01​:45AM +0100\, A. Pagaltzis wrote​:

* Gerard Goossen \gerard@&#8203;tty\.nl [2007-11-07 21​:15]​:

(Strange actually this rigidity\, for a language with such a natural language background\, and claiming to be DWIM\, I guess 'I' currently stands for "somebody more then 10 years ago")

Perl???s original culture is the sysadmin world. Does it surprise you that stability enjoys ultimate priority among its goals?

not having the courage to say that it might be crazy\, error-prone\, etc\, but it is the way it currently works and we're stuck with it.

For my part I did say ???for better or for worse??? regarding autovivification.

Method resolution respecting stubs was a hack put in to deal with AUTOLOAD limitations; the only way to fix the problem it causes is by hacking the hack. As I said\, ???now you have two problems.???

And I would like both hacks to be gone :)

To make the whole OO-method-resolution a lot more sane\,

Method resolution is a red herring. The issue at hand is stubs and forward references\, where Perl 5 does not preserve enough information at the time of stub creation/forward ref taking to be later be able to distinguish them.

I would like to do​: - Skip the 'undef' subs (as already suggested). - Do not allow forward declarations.

If you remove forward declarations it seems to me there is really no need to even have stubs at all.

I am not sure what exactly you mean with a 'stub'. If you mean 'undef' entries in the CODE part of a glob\, then not allowing them is also a very good option. Technically I think you need some kind of "null" entry\, but I think the difference is more in implementation detail then actual difference in behaviour.

- Remove AUTOLOAD

How are people supposed to write proxy objects without AUTOLOAD?

If classes were closed by default and Kurila acquires sane reflection facilities I guess you could use reflection to create methods as needed\, but with open classes that does not seem like an option to me. But then it???s no possible anymore to have a class whose instances proxy objects in different classes\, which is how things like Object​::Trampoline do their job.

You could create a mechanism by which code can be notified of changes to a class\, I guess; then proxies could modify themselves in response to modifications in their proxied classes\, and classes whose instances need to proxy instances of different classes could create new proxy classes at runtime. I suppose.

I???m not sure it would be possible to sanely compose proxies anymore though.

I think you can consider most classes as closed (if they are not using them in combination with proxy class probably won't be a very good idea anyway). Currently the main problem you can't do that is not because they are not closed\, but because reflection is not possible because of AUTOLOAD.

And of course\, you can always do something like $obj->proxy("name") and let "sub proxy" do the magic stuff.

Also\, efficient is something else.

I think AUTOLOAD causes more efficiency problems then it solves\, (especially on the side of the programmer\, using it might be fast initially\, but if you have to find a bug caused by it ...)

Have you already thought of this maybe? Do you possibly already have an approach in mind for how to address this?

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

-- Gerard Goossen TTY Internet Solutions

p5pRT commented 16 years ago

From @davidnicol

no feedback concerning the overloaded p-p explicit weak forward reference approach.

Would it work\, or have I misunderstood an important aspect of the problem?

p5pRT commented 16 years ago

From blblack@gmail.com

A. Pagaltzis wrote​:

* Josh Jore \twists@&#8203;gmail\.com [2007-11-06 15​:55]​:

I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies.

MR responding to stubs was added for a reason. The only way to “fix” this behaviour without obliterating its original and fully intentional functionality is to skip stubs in absence of AUTOLOAD\, but respect them in its presence.

I was thinking along these lines too\, although I don't know if it's worth the effort. But one certainly could make ->can() and method resolution skip stubs in the absence of AUTOLOAD\, confining the current behavior to modules that actually use AUTOLOAD. It would add some method resolution overhead\, but not too much as this stuff gets cached after its first use (at least\, up until it gets redefined again).

-- Brandon

p5pRT commented 16 years ago

From perl-diddler@tlinx.org

Brandon Black via RT wrote​:

A. Pagaltzis wrote​:

* Josh Jore \twists@&#8203;gmail\.com [2007-11-06 15​:55]​:

I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies. MR responding to stubs was added for a reason. The only way to “fix” this behaviour without obliterating its original and fully intentional functionality is to skip stubs in absence of AUTOLOAD\, but respect them in its presence.


  Actually "respect them" in AUTOLOAD's failure or absence\, not just in its presence. It's only when the replacement method has been fully specified that it should override the base method.

I was thinking along these lines too\, although I don't know if it's worth the effort. But one certainly could make ->can() and method resolution skip stubs in the absence of AUTOLOAD\, confining the current behavior to modules that actually use AUTOLOAD. It would add some method resolution overhead\, but not too much as this stuff gets cached after its first use (at least\, up until it gets redefined again).


  This is\, basically\, what I am suggesting as parallel to checking parent methods. If AUTOLOAD fails\, then\, before dying with an Undefined local-method exception\, try looking at parent methods.

  This is would be true OO dynamics not "as expected by Linda Walsh"\, but as defined in Wikipedia. Not that Wkpdia. is the most expert source\, but that my OO expectations are not "wrong" (and OO means whatever some perl-demi-god says they mean) but are reasonable widespread and held by others (at least to the extent as they are defined in the easily accessible Wkpdia.).

  Method overriding is said to provide a method only when a new class provides "a specific implementation" of a method provided by an ancestor. (http​://en.wikipedia.org/wiki/Method_overriding_%28programming%29)

  Perl fails being an OO by this definition. By this definition\, Perl's OO-calling mechanism is broken in regards requiring a "a specific\, (and complete) implementation" of a new method before it overrides a Base method.

  FWIW -- I've held off responding because things were getting too confrontational and I couldn't think of any thing to say to further shed light on my PoV.

p5pRT commented 16 years ago

From chromatic@wgz.org

On Friday 16 November 2007 12​:45​:42 Linda W wrote​:

This is would be true OO dynamics ... Perl fails being an OO by this definition.

Prescriptivist OO dogma has very little to do with Perl\, except that if you stop treating methods as subroutines\, your code will stop breaking.

There is no general purpose way to take a hard reference to a method in a dynamic system such as Perl\, so don't do it. If you do it\, don't complain that your code doesn't work.

If you want to fix what happens when you do that\, you need to provide one of​:

1) a design that will make a strong distinction between subroutines and methods while remaining backwards compatible with existing Perl 5 code (including the test case I posted on 06 November).

2) a general heuristic that can determine whether someone has taken a reference accidentally to something that happens to share the same name as a method in an invokable hierarchy. This may depend also on #1.

I don't think either is possible in Perl 5.

-- c

p5pRT commented 16 years ago

From @ap

* Linda W \perl\-diddler@&#8203;tlinx\.org [2007-11-16 21​:55]​:

A. Pagaltzis wrote​:

* Josh Jore \twists@&#8203;gmail\.com [2007-11-06 15​:55]​:

I'm pretty sympathetic to the idea of method resolution silently skipping over undefined bodies.

MR responding to stubs was added for a reason. The only way to “fix” this behaviour without obliterating its original and fully intentional functionality is to skip stubs in absence of AUTOLOAD\, but respect them in its presence.

Actually "respect them" in AUTOLOAD's failure or absence\, not just in its presence. It's only when the replacement method has been fully specified that it should override the base method.

Your understanding of the phrase “respecting stubs” and your use of it is backwards from what I actually meant by it.

Method overriding is said to provide a method only when a new class provides "a specific implementation" of a method provided by an ancestor. (http​://en.wikipedia.org/wiki/Method_overriding_%28programming%29)

And each of the terms used in that definition can be defined however one likes to define them. “When I use a word\,” Humpty Dumpty said\, in a rather scornful tone


Perl fails being an OO by this definition.

That’s the only way you could find by which Perl’s OO fails to be textbook OO? You didn’t look very hard. Try looking up “encapsulation” for your next trick. (OK\, so inside-out objects fix this and 5.10 includes support to make them reasonably sane in all edge cases. Praise goodness\, it only took 15 years.)

Regards\, -- Aristotle Pagaltzis // \<http​://plasmasturm.org/>

p5pRT commented 16 years ago

From perl-diddler@tlinx.org

chromatic wrote​:

On Friday 16 November 2007 12​:45​:42 Linda W wrote​:

This is would be true OO dynamics ... Perl fails being an OO by this definition. Prescriptivist OO dogma has very little to do with Perl\, except that if you stop treating methods as subroutines\, your code will stop breaking.


My programs work fine. It's perl's OO implementation that I still maintain doesn't fit other people's idea of your "prescriptivist dogma".

There is no general purpose way to take a hard reference to a method in a dynamic system such as Perl\, so don't do it. If you do it\, don't complain that your code doesn't work.


  I'm not complaining that my programs don't work -- that was never the issue. I had 12 different ways to kludge around the problem as suggested by multiple people who didn't understand my complaint.

If you want to fix what happens when you do that\, you need to provide one of​:

1) a design that will make a strong distinction between subroutines and methods while remaining backwards compatible with existing Perl 5 code (including the test case I posted on 06 November).


  I don't recall the particular example you refer to -- I just know that the feature I've given an implementation for in pseudo code is backward compatible and fixes the problem. That you haven't "gotten" that\, yet\, is why I stopped bothering to post -- some people have it set in their mind that I'm complaining about a bug in some program. I'm not. I'm complain that perl doesn't behave in generally expected OO ways. Calling anything other than perl's implementation "prescriptivist dogma" only highlights that perl OO behavior in perl is being defined by perl's implementation\, not generally accepted definitions.

2) a general heuristic that can determine whether someone has taken a reference accidentally to something that happens to share the same name as a method in an invokable hierarchy. This may depend also on #1.


  Irrelevant. The only thing perl needs to do is follow generally accepted practice\, not *your* perl-specific prescriptivist dogma that happens to be broken.

 

p5pRT commented 16 years ago

From perl-diddler@tlinx.org

A. Pagaltzis via RT wrote​:

* Linda W \perl\-diddler@&#8203;tlinx\.org [2007-11-16 21​:55]​: And each of the terms used in that definition can be defined however one likes to define them. “When I use a word\,” Humpty Dumpty said\, in a rather scornful tone



  So perl is a Humpty-Dumpty OO implementation is what you are saying? :-)

Perl fails being an OO by this definition.

That’s the only way you could find by which Perl’s OO fails to be   ^^^^


  Didn't say it was the *only* way. Just "a" way that was done wrong.

textbook OO? You didn’t look very hard. Try looking up “encapsulation” for your next trick. (OK\, so inside-out objects fix this and 5.10 includes support to make them reasonably sane in all edge cases. Praise goodness\, it only took 15 years.)


  I didn't start earnestly trying to use OO features in perl until after I-O objects were already in existence\, so I never experienced their lack. I solved namespace collisions slightly differently\, which was fine for me. Most of my programs are OO in design if not in implementation\, so basic perl worked "fine" for me since before perl had subroutines (Perl 3? early 90's?). My only problem was the broken implementation of requiring new-fully-specified methods to replace old instead of allowing undefined function stubs to generate a fatal error in their place. That's my issue. Perl throws an "undefined" "function/method" error before it tries looking for the method in a parent. I say "reverse it". Try looking up parental methods before dying. That doesn't require any differentiation between functions and methods -- only in how they were called ($s->method\, vs. func($s)).

p5pRT commented 16 years ago

From chromatic@wgz.org

On Friday 16 November 2007 16​:20​:36 Linda W wrote​:

The only thing perl needs to do is follow generally accepted practice...

Who gets to decide what's generally accepted OO practice?

Is dynamic dispatch allowed? (Smalltalk\, Python\, Ruby\, CLOS) Is dynamic dispatch forbidden? (C++\, Java\, C#... sort of) Do attributes have access control? (C++\, Java) Is operator overloading possible for individual objects? (C++\, Ruby) Is there a method_missing feature? (Smalltalk\, Ruby) Are there classes? (C++\, Java\, Smalltalk\, Python\, Ruby) Are there only prototypes? (Self\, JavaScript) Are there metaclasses? (Smalltalk\, Python\, Ruby\, CLOS) Does method dispatch differentiate only on the type of the invocant? (C++... mostly\, Java\, Python) Is all method dispatch generic? (CLOS) Can methods stand alone as first-class entities? (Python) Is the inheritance hierarchy fixed at compile time? (Java\, C#) Are attributes opaque? (Java\, C#\, C++... mostly) Can you add attributes to a class at runtime? (getting sick of listing languages here) Can you add attributes to an instance at runtime? Can you extend built-in classes?   ... at compile time?   ... at runtime? Are there elements of behavior reuse and polymorphism other than the class level? Do overridden constructors dispatch to parent implementations automatically? Are anonymous classes available? Can you create new classes at runtime? Are singleton classes available?

I'm sure there are plenty of other interesting questions about object orientation on which plenty of languages in widespread use now and in the recent past have differed\, so I'm not sure what exactly "generally accepted practice" is\, nor why anyone should be surprised that any particular language doesn't fully meet those mythical criteria.

I think I've finished with this thread\, however.

-- c

p5pRT commented 16 years ago

From @nwc10

On Fri\, Nov 16\, 2007 at 04​:36​:53PM -0800\, Linda W wrote​:

I didn't start earnestly trying to use OO features in

perl until after I-O objects were already in existence\, so I never experienced their lack. I solved namespace collisions slightly differently\, which was fine for me. Most of my programs are OO in design if not in implementation\, so basic perl worked "fine" for me since before perl had subroutines (Perl 3? early 90's?). My only problem was the broken implementation of requiring new-fully-specified methods to replace old instead of allowing undefined function stubs to generate a fatal error in their place.

There are many parts of the Perl implementation that are considered broken\, but still seem to work well enough.

Methods just being subroutines could be considered one of them. The fact that you can take a reference to an as yet undeclared subroutine being another one.

Perl 6 has decided that the latter is not right - in Perl 6 taking a reference to an undeclared subroutine (or method - they are distinct there) is a compile time error.

Maybe we should change it in Perl 5 - it wouldn't kick in until 5.14 though\, as it would have to be a deprecation warning in 5.12\, now that 5.10 is nearly upon us.

At which point we'd solve your problem for you - no surprising run time behaviour.

Nicholas Clark

p5pRT commented 16 years ago

From perl-diddler@tlinx.org

Nicholas Clark via RT wrote​:

There are many parts of the Perl implementation that are considered broken\, but still seem to work well enough.


  Eh? Guess I haven't run into them (or have been subconsciously inculcated into the proper methods as to not hit them...​:-)).

Methods just being subroutines could be considered one of them. The fact that you can take a reference to an as yet undeclared subroutine being another one.


  Well....personally\, I don't recall that as a bug\, "per se"\, as perl is a dynamic language. The undeclared subroutine could be declared at run-time in an "eval"\, for no? What becomes of subroutines caught by "AUTOLOAD"? Or is is not around in P6? Isn't construction of non-existent subroutines that could follow a pre-determined naming convention (such as accessors) considered a useful feature? Or using AUTOLOAD to\, perhaps\, gracefully recover from what might otherwise be a fatal error? Seem to remember some pseudo-perl-shells\, where undefined procedures could be tried in an 'AUTOLOAD' function as external executables.

Perl 6 has decided that the latter is not right - in Perl 6 taking a reference to an undeclared subroutine (or method - they are distinct there) is a compile time error.


  Sigh. I've never used the construct (intentionally\, anyway :-))\, but in a dynamic language\, it seems like it could be a useful feature (or -- best of both worlds\, controllable via a pragma\, perhaps\, where in the "allowing" case\, one could provide "RE's" to describe undefined subroutine patterns that wouldn't be considered an error\, but would allow an AUTOLOAD type handler to be called.

Maybe we should change it in Perl 5 - it wouldn't kick in until 5.14 though\, as it would have to be a deprecation warning in 5.12\, now that 5.10 is nearly upon us.


  From what people have said\, some are using them for 'some reason' (perhaps they want the typing?) for AUTOLOADED functions. If such is truly a widely used feature\, I'd hate to see something like that 'go away' either unnecessarily\, or without some provision for backward compatibility.

  I believe\, I mentioned (or at least I thought it in my head and only though I typed it :-))\, that a "use" (pragma type operation) could specify whether or not to give ancestor function-checking priority over AUTOLOAD\, or AUTOLOAD would be checked first\, and if that fails\, then check ancestors for possible matching methods. AFAIK\, AUTOLOAD isn't an OO-feature\, but it is\, IMO\, an orthogonal feature that\, simply\, isn't part of any generic OO specification\, but may still have great use in Perl(5...). I was planning to rewrite parts of my OO-playground program (the one that some think is "broken") to use AUTOLOAD -- specifically for some similarly structured access functions.

At which point we'd solve your problem for you - no surprising run time behaviour.


  Agreed this might have prevented some "hitting head against the wall" - behaviour on my part\, as some have indicated a desire for -- any solution that solves the particular pitfall I fell into might harm others who are relying on some form of this behaviour\, especially if its use is a widespread as some vehemently assert. :-)

  I don't have a problem with the "undef function" that may or may not be resolved until runtime\, but only the actions taken when it isn't resolved at runtime w/respect to OO-structured calls (blessref->method()). (not addressing the non-OO call case).

  One piece of functionality that is missing -- that might be providable\, is the idea of a "can_autoload(...)" type call being providable as a helper function to autoload. For example\, if I was using autoload to provide accessor functions\, the "can_autoload" func could check allowed fields and return defined or undefined -- but "can_autoload" would depend on the user of "autoload" adding this extra code to new modules that wanted to use it. But this is outside the scope of this particular problem\, I believe.

  In my "idea" world\, if I printed out "\notyetdefinedfunc()" (using print)\, then if AUTOLOAD "fails"\, "undef" be substituted.

  Perhaps it's that I don't see the use of auto-vivifying functions that are not ever fully defined (and can never work). If attempts to define it at runtime fail\, then depending on context ("$a=\notyetdefinedfunc()" vs. trying to call through it could return undef or (if someone tries to call through it) -- then a it would be necessary to generate "attempt to call through undefined subroutine"-Fatal error. But if it was only used as an R-Value\, I would rather see "undef" subbed in. At least that seems like it would provide most or all of today's functionality in a backward compatible way. I'm open to having my mind changed on that point\, but it would seem to be a possible "logical" outcome. But\, again\, calling an undefined function in a "non-OO" way "notyetdefinedfunc($a)" isn't something I was trying to suggest as a "fix" for the current OO-problem case I describe. It's a related issue\, but not exactly the topic of the problem I am describing in this particular problem report.

  If perl made more runtime-resolution decisions regarding "not-fully-defined methods or functions)\, it seems\, might be eliminate the problem I ran into\, but it's hard for me to think through how handling the non-OO case would affect backward compatibility -- which is why I'm only focusing on the OO-call syntax 'side' of the problem.

  Fixing it the way you describe might "solve my issue"\, but I'm not sure how great disallowing compile-time undefined function stubs (or taking address off) would affect the existing base of code and just wanted to voice my opinion\, that I'm not suggesting we "throw out the baby with the bathwater"...(so to speak). Linda

p5pRT commented 16 years ago

From @nwc10

On Sat\, Nov 17\, 2007 at 11​:27​:35AM -0800\, Linda W wrote​:

Nicholas Clark via RT wrote​:

There are many parts of the Perl implementation that are considered broken\, but still seem to work well enough. --- Eh? Guess I haven't run into them (or have been subconsciously inculcated into the proper methods as to not hit them...​:-)).

Methods just being subroutines could be considered one of them. The fact that you can take a reference to an as yet undeclared subroutine being another one.

Perl 6 has decided that the latter is not right - in Perl 6 taking a reference to an undeclared subroutine (or method - they are distinct there) is a compile time error. --- Sigh. I've never used the construct (intentionally\, anyway :-))\, but in a dynamic language\, it seems like it could be a useful feature (or -- best of both worlds\, controllable via a pragma\, perhaps\, where in the "allowing" case\, one could provide "RE's" to describe undefined subroutine patterns that wouldn't be considered an error\, but would allow an AUTOLOAD type handler to be called.

Note\, undeclared\, not undefined.

So this is legal in Perl 6​:

  sub foo;   my $bar = \&foo;

It's just that this is not

  my $bar = \&foo;

where that's the first mention of &foo.

It still lets one have all the flexibility\, it's just that it avoids the possibility of strange side effects and action at a distance.

Nicholas Clark

p5pRT commented 16 years ago

From perl-diddler@tlinx.org

Nicholas Clark wrote​:

On Sat\, Nov 17\, 2007 at 11​:27​:35AM -0800\, Linda W wrote​:

Nicholas Clark via RT wrote​:

There are many parts of the Perl implementation that are considered broken\, but still seem to work well enough. --- Eh? Guess I haven't run into them (or have been subconsciously inculcated into the proper methods as to not hit them...​:-)).

Methods just being subroutines could be considered one of them. The fact that you can take a reference to an as yet undeclared subroutine being another one.

Perl 6 has decided that the latter is not right - in Perl 6 taking a reference to an undeclared subroutine (or method - they are distinct there) is a compile time error. --- Sigh. I've never used the construct (intentionally\, anyway :-))\, but in a dynamic language\, it seems like it could be a useful feature (or -- best of both worlds\, controllable via a pragma\, perhaps\, where in the "allowing" case\, one could provide "RE's" to describe undefined subroutine patterns that wouldn't be considered an error\, but would allow an AUTOLOAD type handler to be called.

Note\, undeclared\, not undefined.


  In my case\, I'm referring to the concept of a "complete implementation" or "fully" specified "method". As near as I can tell\, standard OO concepts don't see a difference between undeclared or undefined. That's specific (in this case) to Perl. OO cares about whether or not you have fully specified a new method.

  By my understand -- I wouldn't consider a "function stub" (created by a previously undefined function reference) as a "full specification" of a new method. For OO's child-methods replacing parent-methods\, an OO compliant language should not throw an error in an OO-syntax call for an undefined method before trying ancestor methods. It seems like a fundamental 'feature' of OO languages. Given how perl generally tries to "do the right thing" and not throw out functionality\, uselessly\, I would think perl would give preference to attempting the OO-parental resolution before calling "Fatal error-undefined method".

So this is legal in Perl 6​: sub foo; my $bar = \&foo;

It's just that this is not my $bar = \&foo;

where that's the first mention of &foo.


  Hmmm. "Once upon a time" I remember writing in Pascal. I wasn't wild about Pascal's requirement to pre-declare functions before use. When I started in 'C' -- and even into more recent times\, it was "standard" practice to NOT pre-declare C functions that existed in the same file. Such functions would be searched for at link time. Of course perl doesn't have a linker\, but isn't the purpose of AUTOLOAD to catch undefined function references and create your own "handler" (die gracefully\, or try loading or creating the function 'on the fly'.

  I "assume" (I hate that word sometimes)\, that there will be a mechanism to support this "on-the-fly" construction in Perl6? If not\, it seems you are dropping functionality that appears to be important in perl5 and might not be easily ported to an environment where on-the-fly definitions aren't allowed.

  Specifically\, if one wants to write "templates" (ala C's macro facility) to produce generic or "accessor" functions\, it seems pretty necessary to support AUTOLOAD catching attempts to use not-fully-defined functions.

  I suppose a workaround for the base bug would be to have an AUTOLOAD function that manually duplicates perl's searching of parent-name spaces for possible valid methods. If it doesn't find one\, then it can die with 'not found' -- (as in the OO case\, it's not trying to dynamically create a method -- just trying to ignore 'stubs' that are not fully specified replacements (consistent with OO practice).

It still lets one have all the flexibility\, it's just that it avoids the possibility of strange side effects and action at a distance.


  I assume perl6 has a different way to allow auto-creation of accessor functions? (Haven't used them\, yet\, in my own perl-OO programming\, but auto-generated methods appear useful as demonstrated in Conway's OO-Perl book. Heh\, I've heard Damian is in the thick of perl6 definition -- if he's going to break that functionality\, he better update his book! :-)

  The change you mention would have prevented the weirdnesses that I ran into (that led to my filing this bug)\, but it would do so at the expense of eliminating certain perl5 features that appear to be very useful. It would appear that perl6's functionality would be hurt by the omission of dynamically-defined methods or functions.

  What happens in perl6\, of course\, doesn't fix parental-method override being broken by taking function stubs as "fully specified child methods".

  FWIW\, I'm glad the rhetoric on this has toned down. With the vehemence I felt in responses\, you'd think this was all "personal" or I stepped on some religious/political ideology. Indeed\, some people's comment that I should accept the word of "perl experts" on "faith" without asking or understanding "why" is\, more than a bit\, characteristic of religious dogma.

p5pRT commented 12 years ago

From perl-diddler@tlinx.org

If one of the new method resolution orders doesn't work\,

an easy way to prevent the problem is to prevent perl from evaluating the "\&method" until runtime. i.e.

Orig program was​: package A; sub method {'method'}; package B; @​ISA=qw(A); sub setup_error{ $x=\&method;} package main; bless my $ref={}\,B; print $ref->method . "\n"; $ref->setup_error(); print $ref->method . "\n";

Simple fix​:

in line w/sub setup_error\, change that to​: sub setup_error{ eval "$x=\&method;"}

Yeah\, it's a hack to get around the original 'hack' implemented for autoload\, but it certainly low cost to implement and requires no work to change perl!

(the things you learn & think of over time...). Of course perl getting much better in 5.10 and improving in 5.12 helps too!

p5pRT commented 12 years ago

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

p5pRT commented 12 years ago

From @cpansprout

On Sun Jul 17 18​:11​:29 2011\, LAWalsh wrote​:

If one of the new method resolution orders doesn't work\,

an easy way to prevent the problem is to prevent perl from evaluating the "\&method" until runtime. i.e.

Orig program was​: package A; sub method {'method'}; package B; @​ISA=qw(A); sub setup_error{ $x=\&method;} package main; bless my $ref={}\,B; print $ref->method . "\n"; $ref->setup_error(); print $ref->method . "\n";

Simple fix​:

in line w/sub setup_error\, change that to​: sub setup_error{ eval "$x=\&method;"}

I don’t think you’re doing what you think you’re doing. :-)

If I add ‘warn $@​’ to the end of setup_error\, I get​:   syntax error at (eval 1) line 1\, near "=" because the $x is interpolated.

If you want to take a reference to a subroutine\, but only if it exists (i.e.\, no autovivving)\, use *method{CODE}.

In fact\, if you want to ignore stubs in method calls\, you could write your own AUTOLOAD to deal with that\, and maybe even put it in a CPAN module. :-)

Yeah\, it's a hack to get around the original 'hack' implemented for autoload\, but it certainly low cost to implement and requires no work to change perl!

(the things you learn & think of over time...). Of course perl getting much better in 5.10 and improving in 5.12 helps too!

p5pRT commented 12 years ago

From perl-diddler@tlinx.org

Father Chrysostomos via RT wrote​:

On Sun Jul 17 18​:11​:29 2011\, LAWalsh wrote​:

If one of the new method resolution orders doesn't work\,

an easy way to prevent the problem is to prevent perl from evaluating the "\&method" until runtime. i.e.

Orig program was​: package A; sub method {'method'}; package B; @​ISA=qw(A); sub setup_error{ $x=\&method;} package main; bless my $ref={}\,B; print $ref->method . "\n"; $ref->setup_error(); print $ref->method . "\n";

Simple fix​:

in line w/sub setup_error\, change that to​: sub setup_error{ eval "$x=\&method;"}

I don’t think you’re doing what you think you’re doing. :-)


  You may be right...I was looking for the constant's bug\, which hit me\, BTW\, because I 'upgraded' my server to openSuSE's latest 11.4 release in May -- this is yet ANOTHER example of needing to repair damage caused by the upgrade

(other things squid\, samba\, most services...oh\, and a minor issue of booting...thank god for repair disks....

  Cripes.

  Anyway\, saw this bug above\, and the problem was stated as the fac that the \&proc\, took the reference at compile time when it wasn't really ready yet.   I figured\, if I delayed the reference till runtime\, after B could figure out it was a 'A'\, and 'A' had a method\, it would work.

  It ran\, so\, why is it not doing what I think it is doing? (I only thought it ran...I don't even remember the original problem anymore\, as it was from 4 years ago)...just looked at the example and remembered the 'use mro' pragma and wondered if that might fix that problem seeing as how I wasn't the only one that noticed the default way of looking for ancestor functions wasn't the place for a 'one size fits all' approach (as was noted at the end of the discussion 4 years ago). While they bug was marked rejected\, I did wish to note that delaying the method lookup until run-time\, seemed to provide the desired effect.

  But w/o the original program to test\, I think it had to do with writing scripts to upgrade my server dist-level manually\, 'live'\, -- much harder work\, but WAY fewer problems after the fact.

  Ya get what ya pay for...(sigh

If I add ‘warn $@​’ to the end of setup_error\, I get​: syntax error at (eval 1) line 1\, near "=" because the $x is interpolated.


  Yeah...the '$x' was a dummy val\, just to take the reference -- if I was writing it today\, I probably would know not to use it cuz not needed. So the warning is superfluous\, as it was the value being returned that was being printed out.