Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Perl: porters

[perl #47181] Try OO semantics before throwing fatal error

 

 

First page Previous page 1 2 Next page Last page  View All Perl porters RSS feed   Index | Next | Previous | View Threaded


perlbug-followup at perl

Nov 5, 2007, 4:51 PM

Post #1 of 35 (664 views)
Permalink
[perl #47181] Try OO semantics before throwing fatal error

# New Ticket Created by Linda Walsh
# Please include the string: [perl #47181]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=47181 >



This is a bug report for perl from perl-diddler [at] tlinx,
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


john.peacock at havurah-software

Nov 6, 2007, 3:25 AM

Post #2 of 35 (641 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


twists at gmail

Nov 6, 2007, 6:54 AM

Post #3 of 35 (642 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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
Attachments: signature.asc (0.18 KB)


nick at ccl4

Nov 6, 2007, 7:07 AM

Post #4 of 35 (640 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


twists at gmail

Nov 6, 2007, 7:38 AM

Post #5 of 35 (642 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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
Attachments: signature.asc (0.18 KB)


john.peacock at havurah-software

Nov 6, 2007, 8:00 AM

Post #6 of 35 (641 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


twists at gmail

Nov 6, 2007, 9:44 AM

Post #7 of 35 (641 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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
Attachments: signature.asc (0.18 KB)


chromatic at wgz

Nov 6, 2007, 10:10 AM

Post #8 of 35 (640 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


john.peacock at havurah-software

Nov 6, 2007, 11:35 AM

Post #9 of 35 (640 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


davidnicol at gmail

Nov 6, 2007, 3:06 PM

Post #10 of 35 (638 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


twists at gmail

Nov 6, 2007, 5:49 PM

Post #11 of 35 (626 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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
Attachments: signature.asc (0.18 KB)


pagaltzis at gmx

Nov 6, 2007, 8:09 PM

Post #12 of 35 (626 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

* Josh Jore <twists [at] gmail> [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/>


ben at morrow

Nov 7, 2007, 9:43 AM

Post #13 of 35 (625 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

Quoth twists [at] gmail (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


nick at ccl4

Nov 7, 2007, 10:29 AM

Post #14 of 35 (624 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


pagaltzis at gmx

Nov 7, 2007, 11:54 AM

Post #15 of 35 (624 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

* Nicholas Clark <nick [at] ccl4> [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/>


gerard at tty

Nov 7, 2007, 12:15 PM

Post #16 of 35 (624 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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


davidnicol at gmail

Nov 7, 2007, 2:06 PM

Post #17 of 35 (625 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

On Nov 7, 2007 12:29 PM, Nicholas Clark <nick [at] ccl4> 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__


pagaltzis at gmx

Nov 7, 2007, 7:01 PM

Post #18 of 35 (625 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

* Gerard Goossen <gerard [at] tty> [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/>


twists at gmail

Nov 7, 2007, 10:15 PM

Post #19 of 35 (625 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

On Wed, Nov 07, 2007 at 05:43:05PM +0000, Ben Morrow wrote:
}
} Quoth twists [at] gmail (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
Attachments: signature.asc (0.18 KB)


pagaltzis at gmx

Nov 8, 2007, 12:24 AM

Post #20 of 35 (622 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

* Josh Jore <twists [at] gmail> [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/>


ben at morrow

Nov 8, 2007, 9:40 AM

Post #21 of 35 (621 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

Quoth twists [at] gmail (Josh Jore):
> On Wed, Nov 07, 2007 at 05:43:05PM +0000, Ben Morrow wrote:
> } Quoth twists [at] gmail (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


gerard at tty

Nov 8, 2007, 12:32 PM

Post #22 of 35 (622 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

On Thu, Nov 08, 2007 at 04:01:45AM +0100, A. Pagaltzis wrote:
> * Gerard Goossen <gerard [at] tty> [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


davidnicol at gmail

Nov 8, 2007, 1:28 PM

Post #23 of 35 (621 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

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?


blblack at gmail

Nov 16, 2007, 9:26 AM

Post #24 of 35 (591 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

A. Pagaltzis wrote:
> * Josh Jore <twists [at] gmail> [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


perl-diddler at tlinx

Nov 16, 2007, 12:45 PM

Post #25 of 35 (592 views)
Permalink
Re: [perl #47181] Try OO semantics before throwing fatal error [In reply to]

Brandon Black via RT wrote:
> A. Pagaltzis wrote:
>> * Josh Jore <twists [at] gmail> [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.

First page Previous page 1 2 Next page Last page  View All Perl porters RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.