Definitions:
============
*) Object: An opaque thingie with properties, attributes, and methods
*) Property: A named thing attached to an object. Properties are
global to the object and public--i.e. there's no implicit hiding,
namespaces, or whatnot. There can be only one foo property on an
object, for example
*) Method: Some sort of action that an object can do. Methods are
global and public--only one foo method for an object. Methods may be
inherited from parent classes, or redefined in a particular class.
Redefined methods hide parent class methods of the same name
*) Attribute: A class-private named slot for an object. Objects can
have multiple attributes of the same name as long as they're in
separate classes, since they're class private.
Behaviours
==========
Now, attributes are *always* data members. They're just slots, at
least conceptually.
Properties and methods share a namespace, and methods win. If I do:
a = foo.bar;
I'll call the bar method of foo if foo has a bar method, otherwise
I'll fetch the bar property. Python does this (right?) and Perl 6
will do this. (Yes, it will. Inside information, trust me. Unless
that changes this week...)
Attributes SHOULD be defined at compile time, but we'll not assume
that they will, so we need to be able to add them at runtime. (We'll
reserve judgement as to whether this is a Good Idea, since we don't
care--we're the "implement semantics" people, not the arbiters of
good and bad semantics)
Methods may dispatch based on call signature
Methods will *not* dispatch based on return type
Classes can redefine their methods at runtime whenever they like
Needs:
======
The interpreter must handle the method/property shadowing.
The interpreter must get in the way of method dispatching, as
everyone gets multimethod dispatch like it or not (though you don't
have to use it)
The interpreter must provide a method dispatch mechanism sufficient
to handle the cases we care about, so we can build a reasonable
method cache. Otherwise our performance will make a PDP-8 look like a
speed demon
The interpreter must handle class hierarchy stuff (parent class,
interfaces inherited) so method caches can be invalidated as need be
for class structure changes
Code must be able to fetch a handle on a particular method for later calling
Maybes:
=======
Does *anyone* need lexically scoped methods? (i.e. a foo method
that's only valid in a particular scope for a particular class,
potentially shadowing another foo method)
I think this is all the pending stuff, and our base OO stuff. Comment
ASAP--my last mail pickup for a while is 5AM EST Tuesday Feb 4...
--
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk
What about redefining methods for a particular object instance?
It's something that Ruby does and can be extremely useful.
> Properties and methods share a namespace, and methods win. If I do:
>
> a = foo.bar;
>
> I'll call the bar method of foo if foo has a bar method, otherwise
> I'll fetch the bar property. Python does this (right?) and Perl 6
> will do this. (Yes, it will. Inside information, trust me. Unless
> that changes this week...)
Will there be some way to explicitly indicate that one is required
but not the other? I can imagine times when you would want to access
a property but not have it masked by a method, or call a method if it
exists but not fall back on a property.
> Code must be able to fetch a handle on a particular method for later calling
By this I presume you mean that the handle would be frozen to the method
as it was when then handle was fetched? If you later re-define the method,
the handle would remain pointing at the original method, not the new one.
Or not?
A
Behind the scenes ruby creates a new (anonymous) subclass,
which contains the new method.
-- jonathan
Nope.
>It's something that Ruby does and can be extremely useful.
Ruby cheats and makes a transparent subclass, which is what we'll
have to do if we want that same functionality.
> > Properties and methods share a namespace, and methods win. If I do:
>>
>> a = foo.bar;
>>
>> I'll call the bar method of foo if foo has a bar method, otherwise
>> I'll fetch the bar property. Python does this (right?) and Perl 6
>> will do this. (Yes, it will. Inside information, trust me. Unless
>> that changes this week...)
>
>Will there be some way to explicitly indicate that one is required
>but not the other? I can imagine times when you would want to access
>a property but not have it masked by a method, or call a method if it
>exists but not fall back on a property.
Yeah, I think there should be for those specialized cases. (And for
inspectors and other low-level thing grubbers)
> > Code must be able to fetch a handle on a particular method for
>later calling
>
>By this I presume you mean that the handle would be frozen to the method
>as it was when then handle was fetched? If you later re-define the method,
>the handle would remain pointing at the original method, not the new one.
Yup.
What about property inheritance?
Jerome
--
jqu...@mongueurs.net
Properties can't get inherited. Properties are runtime additions
tacked on individual objects, and since we're not doing a template
inheritance system there's no way to inherit the things.
> *) Method: Some sort of action that an object can do. Methods are
> global and public--only one foo method for an object. Methods may be
> inherited from parent classes, or redefined in a particular class.
> Redefined methods hide parent class methods of the same name
> Methods may dispatch based on call signature
> The interpreter must get in the way of method dispatching, as
> everyone gets multimethod dispatch like it or not (though you don't
> have to use it)
You appear to contradict yourself. How can their be multimethods, if only
one method named "foo" is allowed per object? (And should I read "object"
as "[object's] class" in the general case?)
Or am I confused - are multimethods actually subroutines, and hence not part
of a class?
Nicholas Clark
Attributes do get inherited, but they're mostly invisible to any
methods but the methods of the class that defines the attributes. (Of
course, it's a SMOP to get them out, and they won't be that hidden,
but...)
Oops, silly me. I was talking about attribute inheritance...
Jerome
--
jqu...@mongueurs.net
It's a little more confusing that that. When I said only one foo
method, it was in contrast to attributes, where an attribute of a
particular name may appear in an object multiple times--since
attributes are class-private, each class in an object's inheritance
hierarchy can safely have an attribute named "foo".
Methods and properties, being global, override each other--a child
class' foo overrides its parent's foo. If the child's foo has
multiple definitions based on signature, or we have foo that crosses
class lines, then the multiple dispatch logic comes online and does
its Weird Magic.
Rereading that, it still doesn't make much sense, but there you go... :)
Just to confuse things more, there is a question I have reguarding
multi-methods and inheritance.
Consider class A defines foo() as a multi-method with 3 different signatures
If class B then sub-classes A and defines a method foo() does it
1 override all foo() methods in A
2 get added to the foo() methods in the dispatch, so we now have
a multi-method with 4 signatures
3 override only the method in A that has the same signature
My guess would be (1) and that multi-method distpatch would
only happen if B called ->SUPER::foo
In which case you could consider that there is only one method
named foo(). That method does the dispatch to the others.
Now I am probably not making sense :)
Graham.
D'oh! That's a good question--I'll ask in a few minutes and find out.
Based on normal OO behaviour, I would assume (3) (which is the same as (2)
if there's no override). the ->SUPER::foo would be called to invoke the
overridden/shadowed version of that signature ...
I would also think that'd be easiest on the parrot, since then it just has
to look for the first thing that matches the signature in all cases,
rather than having logic that checks to see if it needs to invoke the
multimethod logic ... I guess it might slowdown if the override is handled
as a multimethod that goes to the new or callst he next level's multi,
instead of sucking it down and collapsing it for one giant multi ...
--attriel
I got clarification. The sequence is:
1) Search for method of the matching name in inheritance tree
2) if #1 fails, search for an AUTOLOAD
3) if #2 fails (or all AUTOLOADs give up) then do MM dispatch
It looks like if there are multiple methods with the same name in a
class then we do MMD after we find them in step 1, though that's a
little uncertain. (Makes sense to me, though)
Shouldn't we be traversing the inheritance tree once, doing these three
steps at each node until one works, rather doing each step once for the
whole tree. MM dispatch probably complicates this, though.
If my derived class has an autoloaded method which overrides the base class'
method, I don't want the base class method to be called, just because parrot
does things in a peculiar order. Well, I know it's the same order that perl5
does things, but it's still peculiar.
--
Peter Haworth p...@edison.ioppublishing.com
"I'm converting my data to 64-bit signed times, stored big-endian in 8 bytes,
followed by 8 bytes for nanoseconds and attoseconds just in case. This won't
last for more than a few hundred billion years, but neither will the Sun, and
in any case I plan to throw a big programming party on 1 January 2000000001
to upgrade to 128 bits." -- Dan J. Bernstein
I'm no OO expert, but a single traversal sounds right to me too. I am
reminded of various proposals to enhance Perl5's tie interface by allowing
for example, an optional FETCHSLICE method that would be called in
peference to lots of individual FETCHes. This would have caused all sorts
of problems if the FETCHSLICE was later added to a base class, since the
derived class's FETCH method would be ignored in favour of the base
class's new FETCHSLICE method.
--
print+qq&$}$"$/$s$,$*${$}$g$s$@$.$q$,$:$.$q$^$,$@$*$~$;$.$q$m&if+map{m,^\d{0\,},,${$::{$'}}=chr($"+=$&||1)}q&10m22,42}6:17*2~2.3@3;^2$g3q/s"&=~m*\d\*.*g
No, you have to do it multiple times. AUTOLOAD is a last-chance
fallback, so it ought not be called until all other chances have
failed.
>If my derived class has an autoloaded method which overrides the base class'
>method, I don't want the base class method to be called, just because parrot
>does things in a peculiar order. Well, I know it's the same order that perl5
>does things, but it's still peculiar.
If you prototype the sub but AUTOLOAD the body it'll work OK.
Pardon me for coming in in the middle, but it seems to me that only
one traversal should be necessary. The first traversal can accumulate
a temporary linked list of AUTOLOAD subroutines. If the first
traversal locates an appropriate method, the linked list is discarded.
If no appropriate method is found, control is dispatched to the
AUTOLOAD subroutine at the head of the list, if there is one; if the
list is empty the MM dispatch is tried.
<newbie to perl6; I've just joined this mailing list>
How about two AUTO subroutines? An AUTOPROTO method, which will return
the prototype of the subroutine being looked for. If it returns undef,
then we know to keep looking up the inheritance tree. If it doesn't
return undef, cache the prototype (just as if someone had created a stub
for that subroutine with that prototype), and then call AUTOLOAD.
There are a number of benefits of doing it this way:
1/ Just a single traversal of the inheritance tree.
2/ More than one class can have an AUTOLOAD.
2a/ No need for $self->NEXT::AUTOLOAD(@_)
3/ If perl6 allows $coderef = someclass.can('somemethod'), similar
to perl5's UNIVERSAL::can, then this will work right even if
somemethod *would* be autoloaded, but hasn't been created yet,
or if the AUTOLOAD method chooses not to cache a subroutine for
it. (.can would would search the inheritance tree (once), and
call AUTOPROTO as needed, but would not call AUTOLOAD)
Item (2) is perhaps the most important, since none of the other things
in this thread seem to address it.
</newbie>
--
$;=qq qJ,krleahciPhueerarsintoitq;sub __{0 &&
my$__;s ee substr$;,$,&&++$__%$,--,1,qq;;;ee;
$__>2&&&__}$,=22+$;=~y yiy y;__ while$;;print
Redefining methods is almost (but not quite) as evil as altering
inheritance trees (at least wrt to it's effect on caching methods).
Consider the following perl5 code:
{ package MyClass; sub SomeMethod { 12 } }
my $methodref = MyClass->can("SomeMethod");
*MyClass::SomeMethod = sub { return 42 };
print MyClass->SomeMethod(), "\n";
print MyClass->$methodref(), "\n";
I suppose if perl6's equivilant of 'can' returns a string, such as
"MyClass::SomeMethod", then it might work as you want it to... but that
would produce one extra level of indirection; would it be worth it?
So? This is perl, it happens with some frequency, and other languages
we'll be running (like Ruby) do it rather more than perl does.
Doesn't matter if we like it or not, it's going to happen so we deal
with it. There are optimization tricks we can use, but they need to
be behind-the-scenes tricks and not affect language semantics.
Fair enough--in practice we can do a single traversal, but
conceptually we need to do multiple traversals. More importantly we
can't check for method then AUTOLOAD then MMD in each class in turn
up the hierarchy, which is what I think the original suggestion was.
(Though I may have misinterpreted, of course)
If A isa B, we certainly wouldn't want to call A's AUTOLOAD on a
method before we looked to see if B had a concrete instance of that
method.
I haven't said that we should rule out method redefinition... I am,
however, saying that we should handle it no worse than (and preferably
better than) perl5 does it.
My bit of example code was merely to demonstrate that UNIVERSAL::can()
from perl5 clearly has the problem that Andy Wardley worries about wrt
"freezing" to a particular definition... Thus, it *may* be a good idea
to *not* provide a user-code-level means of obtaining method handles, or
else it will likely have the same problem as perl5's ->can(). In other
words, I'm agreeing with you -- any method-handle-obtaining-for-caching
should be entirely behind the scenes, where we can easily keep track of
whether a cached handle is still valid.
Right. The best you could probably do is note where you found the first AUTOLOAD
so that when you do reach the end of the ISA search you don't need to do
the whole search again.
But is this programming for the common case ? or is it premature
optimization.
Graham.
Unless we changed the language in such a way that we could *tell*
whether or not we should try calling A's AUTOLOAD.
Currently, in perl5, if you have "package A; sub foo;", then the method
search will stop in A and call A's autoload, since it *knows* that A has
an appropriate method.
Obviously, we don't really want to force our users to stub every method
(though this would be *one* way of avoiding the need for a second pass
for AUTOLOADs)... If the language had an AUTOPROTO/AUTOSTUB if some
sort, we could call it and find out where the heirarchy search should
stop in that class.
> But is this programming for the common case ? or is it premature
> optimization.
Well, first ask what are the common cases for autoloading in perl5...
I think that the *most* common case is AutoLoader/SelfLoader.
If Devel::SelfStubber is used with either of those, then that stops the
heirarchy search for methods in the right place, not needing a second
pass.
There are also definitions of XS constants ... though these are not, in
general, used as methods, so I suppose we can ignore them for now.
And finally, there are object property accessors, so that one can write
$c = $obj->color, instead of $c = $obj->{color}. These are sometimes
done in AUTOLOAD... But stubs are rarely, if ever, provided for them, so
calling this type of method almost always requires two passes through
the inheritance heirarchy.
.....
There's also another case that's not-so-common, but mainly due to the
difficulties of doing it right in perl5. You've suggested keeping track
of where we found the *first* AUTOLOAD ... but what happens if we want
to inherit from *two* classes with AUTOLOAD methods? In perl5, you'd
have to use NEXT.pm, which, imho, is fairly ugly internally, and not
especially efficient (plus it's not in the core). Perl6 should have a
built-in mechanism to allow an AUTOLOAD method to either make a call to
the next AUTOLOAD, a la NEXT.pm, (this might be fairly expensive), or
throw an exception saying that that particular method isn't supplied by
this AUTOLOAD, and have the search continue (possibly much less
expensive).
I'm thinking premature optimization, and if not that at least
something that can be put off until later.
Given that we have to run perl 5 code with the same expressed
semantics as perl 5, and also are going to run python and ruby code
properly, this isn't a tenable option.
We're the implementors. While we can complain about the semantics we
have to express, we don't get to not express them.
No. Python allows fetching a handle to the current method definition,
and it seems a reasonable thing in some circumstances, so it needs to
be supported. They may be the wrong answer in many circumstances, but
that doesn't mean they're the wrong answer in all circumstances.
Nothing says that we can't have a different semantic for each language
we're running.
When running perl5 code, we could fetch methods and perform method
caching one way, and when running perl6 code, we could fetch methods and
perform method caching a different way... and possibly a different
technique for each of python and tcl.
I was going to say that I probably ought to write my idea up in an RFC,
and see how people react, and get Larry's approval... but, I discovered
that someone else thought of this idea before me, and wrote it up!
http://dev.perl.org/rfc/232.pod
Well, almost nothing. Nothing much besides me, at least.
This isn't the place to ponder alternate semantics for existing or
proposed languages. That's what the language lists are for. If you
want perl 6 to behave in some particular way, go to perl6-language or
petition Larry. (I'd not suggest bringing it up on Python-dev, but if
you want to brave it, well, good luck)