Since autrijus is now busy porting the P5 metamodel prototype into Haskell for use in Pugs, I have decided to begin work on documenting the Perl6::MetaModel prototype modules more thoroughly. The first step I see in this is to define a Meta Object Protocol (aka - the stuff you can do with/to $obj.meta).
I have reviewed the relevant sections in Syn/Apoc 12 and am now writing a small add-on (I am calling it Syn 12.5 for now) which I hope will can augment the relevant sections from Syn/Apoc 12. As soon as the document is complete enough, I will post it here, or you can see it here (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/) as it is being developed. I welcome all comments, questions and suggestions .... oh, and help too :).
This now brings me to the second item mentioned in the subject line.
So..., as far as I see it, the following statements are true about the metamodel.
1) MetaClass is a subclass of Object 2) MetaClass is an instance of MetaClass
So the following code should be true (given a random instance $obj).
$obj.meta.isa(MetaClass); $obj.meta.isa(Object);
Because after all, the object returned from $obj.meta should be a MetaClass instance right?
However, Syn/Apoc 12 shows that the following is true if $foo is an instance of the Foo class.
$foo.meta.isa(Foo)
And that $foo.isa(Foo) actually is just an alias for $foo.meta.isa(Foo).
So I am sure you can see my problem here.
The p5 prototype currently handles it as such:
$foo->isa(Foo) # returns true if $foo is an instance of Foo $foo->meta->isa(MetaClass) # returns true since $foo->meta returns a MetaClass instance $foo->meta->is_a(Foo) # returns true, note the added '_'
Personally I am not a fan of the 'is_a' name, I just did it one day, and it sort of stuck. But I do think we need to find a way to differentiate between the two questions:
- What class are you an instance of? - What class are you describing?
The first question can be asked of anything which inherits from Object. The second question is really only relevant to MetaClass instances.
Coming in late here, but it seems odd to have an actual class called "MetaClass". The meta-object protocols with which I am familiar have the concept of a metaclass (a class whose instances are themselves classes), and the class Class is such a metaclass, but where does a class named MetaClass fit in? If all metaclasses are instances of MetaClass, then MetaClass must be an instance of itself - is this then the only cycle in the graph?
> 1) MetaClass is a subclass of Object > 2) MetaClass is an instance of MetaClass
OK.
> So the following code should be true (given a random instance $obj).
> However, Syn/Apoc 12 shows that the following is true if $foo is an > instance of the Foo class.
> $foo.meta.isa(Foo)
Hm. That doesn't make sense to me at all. Clearly I need to reread the Syn/Apoc. I'd expect $foo.isa(Foo) and that's it, although if nothing fancy with composition is going on $foo.class == Foo would also be true.
> Coming in late here, but it seems odd to have an actual class called > "MetaClass". The meta-object protocols with which I am familiar have > the > concept of a metaclass (a class whose instances are themselves > classes), and > the class Class is such a metaclass, but where does a class named > MetaClass > fit in?
I discussed with Larry at the hackathon about the role that Class played in the metamodel. We decided that is was but a thin veneer between the meta-land and the user-land. I assume this is still the case. Here is a 10,000 ft view of the metamodel prototype I sketched out the other day (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ 10_000_ft_view.pod). It should shed a little light on this discussion.
As for how this differs from the other MOPs out there. I took the basic design of MetaClass, Class, Object from Smalltalk -80 actually, but modified the relationships a little to be more has-a the is-a. Let me expand/digress on this slightly ..
The basic Smalltalk-80 idea of every user-level Class having an associated meta-level Class is still retained. However in Smalltalk, Class is an instance of MetaClass, where in the metamodel Class has-a instance of MetaClass. And as I said, Class is really nothing special, it but a level of indirection between the instance and MetaClass instance.
I also borrowed many ideas from CLOS (in particular from book "The Art of the MetaObject Protocol"). CLOS is more like what you describe, where standard-class is the metaobject to define classes. I see this as mapping to the MetaClass, and our Class as being something akin to the find-class generic function in CLOS.
> If all metaclasses are instances of MetaClass, then MetaClass must > be an instance of itself - is this then the only cycle in the graph?
Yes, that is the cycle.
>> 1) MetaClass is a subclass of Object >> 2) MetaClass is an instance of MetaClass
> OK.
>> So the following code should be true (given a random instance $obj).
> What does $obj.meta return - is it just a shortcut for > $obj.class.class, or > is something else going on here?
Well, I did not see $obj.class speced in A/S12 so I never did anything with that. However the p6opaque instance structure I use in the prototype metamodel has a pointer back to the class object (see the 10,000 ft view again). So it is simple to implement it if we want too.
But to answer your question, I was always under the impression that $obj.meta returned the MetaClass instance associated with the class that $obj is an instance of.
However, keep in mind, these are somewhat fuzzy areas in Syn/Apoc12, and all details about $obj.meta only deal with "Introspection".
<best pirate voice> Arghhh, these be uncharted waters 'mah Boy! </best private voice>
> If the former, then all of these should be true.
> $obj.isa(Object)
yup, this will always be true.
> $obj.class.isa(Object) > $obj.class.isa(Class)
Again, no .class that I know of, however if there is, then these too should be true.
I will agree with 1 and 3, but not with 2. I see Class and MetaClass are seperate things, at least how I coded it. However this, should be true (assuming we introduce a .class method):
$obj.meta.class.isa(Class)
However this is not a closed issue, so we can discuss it if you see a real need for things to be this way.
>> However, Syn/Apoc 12 shows that the following is true if $foo is an >> instance of the Foo class.
>> $foo.meta.isa(Foo)
> Hm. That doesn't make sense to me at all. Clearly I need to reread > the > Syn/Apoc. I'd expect $foo.isa(Foo) and that's it, although if nothing > fancy > with composition is going on $foo.class == Foo would also be true.
We have instance methods and class methods now in Perl 6, as well as instance attributes and class attributes. The way I view Class objects are as such:
A Class object is to class methods as an instance is to instance methods.
Meaning, the Class object will be invocant of all the class methods. It is of course possible to also then have the metaobject protocol act upon that class object (meaning the methods defined in the meta-object protocol would have the class object as the invocant), but in my mind that could present namespace issues. For instance, the meta-object protocol which is begun in Apoc/Syn 12 talks about a .name, .version and .authority methods. I could see very easily where the meta-object protocol could conflict with user defined class methods of the same name.
So by having the Class objects be the invocants for class methods, and the MetaClass objects be the invocants for the methods defined by the meta-object protocol, we are avoiding any namespace clashes.
> On Aug 8, 2005, at 4:26 PM, Mark Reed wrote: >> Coming in late here, but it seems odd to have an actual class called >> "MetaClass". The meta-object protocols with which I am familiar have >> the >> concept of a metaclass (a class whose instances are themselves >> classes), and >> the class Class is such a metaclass, but where does a class named >> MetaClass >> fit in?
> I discussed with Larry at the hackathon about the role that Class > played in the metamodel. We decided that is was but a thin veneer > between the meta-land and the user-land. I assume this is still the > case. Here is a 10,000 ft view of the metamodel prototype I sketched > out the other day > (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ > 10_000_ft_view.pod). It should shed a little light on this discussion.
> As for how this differs from the other MOPs out there. I took the > basic design of MetaClass, Class, Object from Smalltalk -80 actually, > but modified the relationships a little to be more has-a the is-a. Let > me expand/digress on this slightly ..
> The basic Smalltalk-80 idea of every user-level Class having an > associated meta-level Class is still retained. However in Smalltalk, > Class is an instance of MetaClass, where in the metamodel Class has-a > instance of MetaClass. And as I said, Class is really nothing special, > it but a level of indirection between the instance and MetaClass > instance.
> I also borrowed many ideas from CLOS (in particular from book "The Art > of the MetaObject Protocol"). CLOS is more like what you describe, > where standard-class is the metaobject to define classes. I see this > as mapping to the MetaClass, and our Class as being something akin to > the find-class generic function in CLOS.
>> If all metaclasses are instances of MetaClass, then MetaClass must >> be an instance of itself - is this then the only cycle in the graph?
> Yes, that is the cycle.
>>> 1) MetaClass is a subclass of Object >>> 2) MetaClass is an instance of MetaClass
>> OK.
>>> So the following code should be true (given a random instance $obj).
>> What does $obj.meta return - is it just a shortcut for >> $obj.class.class, or >> is something else going on here?
> Well, I did not see $obj.class speced in A/S12 so I never did anything > with that. However the p6opaque instance structure I use in the > prototype metamodel has a pointer back to the class object (see the > 10,000 ft view again). So it is simple to implement it if we want too.
> But to answer your question, I was always under the impression that > $obj.meta returned the MetaClass instance associated with the class > that $obj is an instance of.
> However, keep in mind, these are somewhat fuzzy areas in Syn/Apoc12, > and all details about $obj.meta only deal with "Introspection".
> <best pirate voice> > Arghhh, these be uncharted waters 'mah Boy! > </best private voice>
>> If the former, then all of these should be true.
> I will agree with 1 and 3, but not with 2. I see Class and MetaClass > are seperate things, at least how I coded it. However this, should be > true (assuming we introduce a .class method):
> $obj.meta.class.isa(Class)
> However this is not a closed issue, so we can discuss it if you see a > real need for things to be this way.
>>> However, Syn/Apoc 12 shows that the following is true if $foo is an >>> instance of the Foo class.
>>> $foo.meta.isa(Foo)
>> Hm. That doesn't make sense to me at all. Clearly I need to reread >> the >> Syn/Apoc. I'd expect $foo.isa(Foo) and that's it, although if >> nothing fancy >> with composition is going on $foo.class == Foo would also be true.
Up until today, I thought I had a good idea of how your metamodel works, but now I'm confused. My main sticking point is that a class Foo seems to have three different aspects:
Foo class(Foo) meta(Foo)
For each of these, could you please try to explain: 1) Roughly what its responsibility is (and how it relates to the others) 2) Whether it is actually an object 3) If so, what its class is
I realise that some of these details are probably spread around Synopses, source code, and the inside of your own head, but it would really help to have a concise, clear definition of each.
So far, this is what I have picked up; some/most of it is probably wrong:
~ Foo ~ Is a type that variables etc. can be declared to have Is not an object => I'm really not sure about this...
~ class(Foo) ~ Used as the invocant of class methods => Any other purpose? Is an object; instance of the 'Class' class => How do we get properly-typed access to members that class(Foo) has that aren't declared in 'Class'?
~ meta(Foo) ~ Members contain info /about/ Foo, rather than /of/ Foo => This is to avoid name-clashes with 'name', 'authority' etc. Is an object; instance of the 'MetaClass' class
> Stevan Little wrote: >> Here is a 10,000 ft view of the metamodel prototype I sketched out >> the other day >> (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ >> 10_000_ft_view.pod). It should shed a little light on this >> discussion.
> There you have
> i(Foo) - instance of Foo > Foo - the user-level Foo class > class(Foo) - the instance of Perl6::Class named "Foo" > meta(Foo) - the instance of Perl6::MetaClass which describes Foo
> The thing which is clear to everybody---even including stupid me---is > that > there is a 1:n relation between Foo and i(Foo). But then comes a three > part > referential chain Foo -> class(Foo) --> meta(Foo) that to me is > conceptually > *one* thing. The levels of indirection are implementation details, > right?
Yes, and no. Please see the second email I sent to Mark. It explains the role I see for ::Class instances, and why they are not just ::MetaClass instances.
Also please keep in mind that I am an implementation monkey, and so most anything I am documenting is likely to be the implementation and not the theory. So assuming things are "implementation details" is usually the right assumption :)
> The next level where a 1:n relation exists is below meta(Foo) to pure > meta.
Not entirely, class models are not as neat and tidy as type models, you have many more cycles. To start with, meta(MetaClass) is an instance of MetaClass (this is the traditional object model cycle), it is also a subclass of Object, and then meta(Object) is also an instance of MetaClass.
However since this is cyclical, you end up with the "Which came first, the chicken of the egg?" issue. So in the implementation I have created, the "X instance of X" part is accomplished through a has-a relationship with the ::Class intsances, so that a ::Foo instance has-a ::Class instance which has-a ::MetaClass instance. Throw in some AUTOLOAD trickery and you have a prototype.
> Am I missing something? Conceptually I see *one* MetaClass which > manages > its class instances which in turn manage their object instances.
No, there is no *one* MetaClass to manage them all. AFAIK this was something they tried with Smalltalk 72 and found it was problematic, so they went to the "every Class instance has a MetaClass instance" and things worked out much better. However since I was not alive (and certainly not programming) in '72 I cannot give you any more details that that.
> OK, it's slightly more complicated because classes can have class > instances
That does not make it any more complicated. If you think of ::Class instances as being like regular instances, only just acting upon the class level methods and attributes, you can see that things are pretty consistent.
> and > there is multiple inheritance that adds edges into the tree which > transform > it into a DAG.
Nothing in an object model is ever a DAG, there are always cycles. And MI does not complicate things either, a MetaClass just holds a list of superclasses, thats it, nothing more.
> And I see also classless objects.
Yes, but those are not going to be handled in the meta-model, because the meta-model is all about classes. You can however, build a classless system on top of the metamodel, using classes of course.
Ahhh, the circularity of it all :)
Once you get used it it, it is really a beautiful thing.
Stuart Cook wrote: > So far, this is what I have picked up; some/most of it is probably wrong:
At least your confusion matches nicely with mine :)
> ~ Foo ~ > Is a type that variables etc. can be declared to have > Is not an object > => I'm really not sure about this...
Bare Foo is a namespace lookup. The associated type is something like 'direct instance of Foo'. It is checked with the .does method. This type is then used as type parameter to constrain one of the Fantastic Four ($&@%):
my Foo $foo; # $foo now of type 'Undef of Foo'
foo = Foo.new; # type correct because Foo.new.does(Foo)
> ~ class(Foo) ~ > Used as the invocant of class methods > => Any other purpose? > Is an object; instance of the 'Class' class
From the type system point of view class(Foo) is a Class type. But that is what bare Foo means anyway if the innermost entry in the namespace was generated from the class special form.
> => How do we get properly-typed access to members that class(Foo) has > that aren't declared in 'Class'?
Sorry, I don't understand that. What do you want to access? Private class data? Or even lower level implementation details? Everything else should be accessible through namespace syntax:
&Foo::action(); # action call through Code ref $Foo::attr; # data slot access @Foo::attr[42] # array slot
given Foo # binds block owner $/ to Foo, $_ from outside { &::action(); # &action() etc. work as well $::attr; @::attr[42];
# or with my idea of slot accessor expressions # bound through $/ := Foo
&.action(); $.attr; @.attr[42];
# or with method dispatch that does not necessarily # end up calling a slot in Foo
my method action # hide OUTER::action { say "no Foo method but invocant.does(Foo) is $/.does(Foo)"; # what would next METHOD call here? } # Note that 'my multi method action' would temporarily install # action in an existing outer multi or create a new local one and # and install an outer non-multi in it or some such. # I'm not the dispatch Guru ;)
.action(); # prints "no Foo method but invocant.does(Foo) is true" .attr; # MMD could select Foo::Item::attr accessor .attr[42]; # MMD could select &postfix:<[ ]>(Foo::Array::attr, 42) }
> ~ meta(Foo) ~ > Members contain info /about/ Foo, rather than /of/ Foo > => This is to avoid name-clashes with 'name', 'authority' etc. > Is an object; instance of the 'MetaClass' class
If avoiding name clashes is all, a simple Foo::META pseudo namespace and %META hash would do. Why a MetaClass and instances of it?
I hope that .isa, .does and .meta are normal Method subtypes and *not* slots on some implementation objects/structures. -- $TSa.greeting := "HaloO"; # mind the echo!
On Tue, Aug 09, 2005 at 06:36:28PM +0200, TSa wrote: > But Smalltalk is a typeless language that dispatches along the lines > of the (meta)class/(meta)object links. I propose to call this kind > of thing slot dispatch and reserve single and multi method dispatch for > the type based approach. Don't get me wrong, I consider them all as > equally usefull tools that belong into a state of the art programming > language. The only question is which gets the nicest syntax. And I > guess the meta model by its nature of beeing 'behind the illusion > of simplicity' has to take the burden of beeing somewhat uglier or > more verbose or some such.
Perl 6 in its unannotated form is also (mostly) a typeless languages, with only the five builtin types, much like Perl 5 is.
I suspect that the unannotated form will be the form most program begins, which is why they are (naturally) shorter than annotated forms.
As you add more types and turn on optimization settings, the inferencer/typechecker kicks in, and you get more static bindings; however, the metamodel still exist at runtime, and it is with it that most runtime reflection is performed.
> >Yes, but those are not going to be handled in the meta-model, because > >the meta-model is all about classes. You can however, build a classless > >system on top of the metamodel, using classes of course.
> Could it be the case that choosing the same terms 'class' and 'object' > on the meta level as on the user level is a *bad* idea? At least it > will be a source of confusion.
I think the meta- prefix is what caused much of the initial conclusion. When I first heard "metatheory", I also thought it was some kind of ontological mystery. Turns out that "meta" in this context coincides with "guts", as in "perlguts" -- i.e., something that happens at the internals level.
So, think of them more like "Internal Objects" and "Internal Classes", or "Object Guts" and "Class Guts"...
> >Ahhh, the circularity of it all :) > What is the benefit of the circularity?
The benefit is that the implementor won't need to implement a countless set of turtles all the way down. :)
> >Once you get used it it, it is really a beautiful thing.
> Infinite recursion is a great mental tool, indeed. > But somewhat difficult to implement without either > infinite processing time or infinite memory :)
Nah, lazy evaluation is the canonical solution to this! (Sorry, can't resist it.)
you know that a formal German greeting in a collequial environment can be interpreted as unfriendly? I don't do that but just wanted to state the fact.
>> The next level where a 1:n relation exists is below meta(Foo) to pure >> meta.
> Not entirely, class models are not as neat and tidy as type models, you > have many more cycles. To start with, meta(MetaClass) is an instance of > MetaClass (this is the traditional object model cycle), it is also a > subclass of Object, and then meta(Object) is also an instance of MetaClass.
> ---> is subclass of > ...> is instance of
I'm not a good meta modeler---actually I'm none at all. But I get as much as that you built a referential fabric between five data structures. Some of them are used for walking 'up the instanciation chains' and the other for hangling along the 'subclassing links'. But what exactly is the difference between these two? What are they used for?
> However since this is cyclical, you end up with the "Which came first, > the chicken of the egg?" issue. So in the implementation I have created, > the "X instance of X" part is accomplished through a has-a relationship > with the ::Class intsances, so that a ::Foo instance has-a ::Class > instance which has-a ::MetaClass instance. Throw in some AUTOLOAD > trickery and you have a prototype.
So, you basically create the gang of five above "from the outside" and link them together. I've no problem with that.
>> Am I missing something? Conceptually I see *one* MetaClass which manages >> its class instances which in turn manage their object instances.
> No, there is no *one* MetaClass to manage them all. AFAIK this was > something they tried with Smalltalk 72 and found it was problematic, so > they went to the "every Class instance has a MetaClass instance" and > things worked out much better. However since I was not alive (and > certainly not programming) in '72 I cannot give you any more details > that that.
But Smalltalk is a typeless language that dispatches along the lines of the (meta)class/(meta)object links. I propose to call this kind of thing slot dispatch and reserve single and multi method dispatch for the type based approach. Don't get me wrong, I consider them all as equally usefull tools that belong into a state of the art programming language. The only question is which gets the nicest syntax. And I guess the meta model by its nature of beeing 'behind the illusion of simplicity' has to take the burden of beeing somewhat uglier or more verbose or some such.
>> OK, it's slightly more complicated because classes can have class >> instances
> That does not make it any more complicated. If you think of ::Class > instances as being like regular instances, only just acting upon the > class level methods and attributes, you can see that things are pretty > consistent.
Hmm, again: what distinguishes classes from objects and meta classes from meta objects? I mean other then beeing different nodes in a referential fabric? BTW, is there a good name for it? I guess Matrix is also over-used.
My view is that Perl6 should have a name tree, a type lattice and a meta graph/model/fabric?
>> and >> there is multiple inheritance that adds edges into the tree which >> transform >> it into a DAG.
> Nothing in an object model is ever a DAG, there are always cycles. And > MI does not complicate things either, a MetaClass just holds a list of > superclasses, thats it, nothing more.
>> And I see also classless objects.
> Yes, but those are not going to be handled in the meta-model, because > the meta-model is all about classes. You can however, build a classless > system on top of the metamodel, using classes of course.
Could it be the case that choosing the same terms 'class' and 'object' on the meta level as on the user level is a *bad* idea? At least it will be a source of confusion.
> Ahhh, the circularity of it all :)
What is the benefit of the circularity?
> Once you get used it it, it is really a beautiful thing.
Infinite recursion is a great mental tool, indeed. But somewhat difficult to implement without either infinite processing time or infinite memory :) -- $TSa.greeting := "HaloO"; # mind the echo!
> Up until today, I thought I had a good idea of how your metamodel > works, but now I'm confused. My main sticking point is that a class > Foo seems to have three different aspects:
> Foo > class(Foo) > meta(Foo)
> For each of these, could you please try to explain: > 1) Roughly what its responsibility is (and how it relates to the > others) > 2) Whether it is actually an object > 3) If so, what its class is
I will simply add to your explanations below (the are mostly correct). Keep in mind, as I said to TSa, I am coming from a implementation point of view, and so much of what I descibe will be about the implementation.
> I realise that some of these details are probably spread around > Synopses, source code, and the inside of your own head, but it would > really help to have a concise, clear definition of each.
Yes, sorry. This is why I am trying to document it now.
> So far, this is what I have picked up; some/most of it is probably > wrong:
> ~ Foo ~ > Is a type that variables etc. can be declared to have
That is one way to look at it I suppose. The reality is that there will be no actual 'Foo', at least not in the metamodel. 'Foo' is a magical interpreter concept, which is really just an alias/pointer/level-of-indirection/whatever for class(Foo).
This is all, of course, implementation details.
> Is not an object
Nope... its magic :)
> => I'm really not sure about this...
ahh, but you were correct. Trust your instincts Stuart < the force is strong with this one I think >
> ~ class(Foo) ~ > Used as the invocant of class methods
Yes. It is also the connection between the concrete instance and concrete metaclass instance.
> => Any other purpose?
In autrijus's version of the model it also stores the index of the attribute in the instance storage array. But other than that, no it has no other purpose in my eyes.
> Is an object; instance of the 'Class' class
Perl6::Class in the p5 metamodel. I also find adding either the Perl6:: or just :: at the front of names like 'Class' are helpful.
> => How do we get properly-typed access to members that class(Foo) has > that aren't declared in 'Class'?
class(Foo) instance methods will be for 'Foo', and the class methods will be for ::Class.
The current metamodel hacks this in a kind of ugly way, but that is how I am seeing it.
> ~ meta(Foo) ~ > Members contain info /about/ Foo, rather than /of/ Foo
Yes, the metaclass basically stores the name, version, authority, superclass list, private method table, public method table and attribute list. All the things which make up a class (yes, I am fluffing the details here a bit, but you get the idea).
> => This is to avoid name-clashes with 'name', 'authority' etc.
That is not really the reason, but yes it does mean that there are no restrictions placed on class methods for 'Foo'.
> you know that a formal German greeting in a collequial > environment can be interpreted as unfriendly? I don't > do that but just wanted to state the fact.
My apologies, no unfriendliness intended :)
>>> The next level where a 1:n relation exists is below meta(Foo) to >>> pure meta. >> Not entirely, class models are not as neat and tidy as type models, >> you have many more cycles. To start with, meta(MetaClass) is an >> instance of MetaClass (this is the traditional object model cycle), >> it is also a subclass of Object, and then meta(Object) is also an >> instance of MetaClass. >> ---> is subclass of >> ...> is instance of
> I'm not a good meta modeler---actually I'm none at all.
They are icky beasts and can cause ulcers, I suggest avoiding them at all costs :)
> But I get as much as that you built a referential fabric > between five data structures. Some of them are used > for walking 'up the instanciation chains' and the other > for hangling along the 'subclassing links'. But what exactly > is the difference between these two? What are they used for?
Actually I think it is 4 data structures, if I understand your question correctly. 1) the instance, 2) the magic 'Foo' class, 3) the class(Foo) (is instance of Perl6::Class) and 4) meta(Foo) (an instance of Perl6::MetaClass).
They are mostly used for walking 'up the instanciation chains' for things like;
- to collect all relevant attributes - method dispatch - ordered destruction - etc.
I do not hangle along the 'subclass links' because I actually don't store subclass links. I considered adding them, but to be honest, I have yet to encounter a real use for them short of introspection.
>> However since this is cyclical, you end up with the "Which came >> first, the chicken of the egg?" issue. So in the implementation I >> have created, the "X instance of X" part is accomplished through a >> has-a relationship with the ::Class intsances, so that a ::Foo >> instance has-a ::Class instance which has-a ::MetaClass instance. >> Throw in some AUTOLOAD trickery and you have a prototype.
> So, you basically create the gang of five above "from the outside" > and link them together. I've no problem with that.
Yes, basically, this is the bootstrapping code. It is the ugly underbelly of the metamodel.
>>> Am I missing something? Conceptually I see *one* MetaClass which >>> manages >>> its class instances which in turn manage their object instances. >> No, there is no *one* MetaClass to manage them all. AFAIK this was >> something they tried with Smalltalk 72 and found it was problematic, >> so they went to the "every Class instance has a MetaClass instance" >> and things worked out much better. However since I was not alive (and >> certainly not programming) in '72 I cannot give you any more details >> that that.
> But Smalltalk is a typeless language that dispatches along the lines > of the (meta)class/(meta)object links. I propose to call this kind > of thing slot dispatch and reserve single and multi method dispatch for > the type based approach. Don't get me wrong, I consider them all as > equally usefull tools that belong into a state of the art programming > language. The only question is which gets the nicest syntax. And I > guess the meta model by its nature of beeing 'behind the illusion > of simplicity' has to take the burden of beeing somewhat uglier or > more verbose or some such.
Yes, the metamodel will surely have many ugly and verbose corners. This is expected for bootstrapping a reflective metamodel of this kind.
As for your dispatch-ing point. I am not sure I understand what you are saying, it seems almost as if you are arguing for a generic-function approach like CLOS/Dylan rather than a methods-stored-in-class approach like most mainstream OO. Is that correct, or am I reading in too far?
IMO, generic functions are really really really really nice things. However, they are hard to understand for most programmers, so they are not really viable (unless you hide them under a nice UI).
>>> OK, it's slightly more complicated because classes can have class >>> instances >> That does not make it any more complicated. If you think of ::Class >> instances as being like regular instances, only just acting upon the >> class level methods and attributes, you can see that things are >> pretty consistent.
> Hmm, again: what distinguishes classes from objects and meta classes > from > meta objects?
Nothing, everything is an Object (for the most part, that is). The distinction between meta-level and user-level (or as they call it in The Art of MOP, backstage and on-stage) is really an artificial barrier which the interpreter sets up. The purpose of the meta-object protocol is to document how much of the backstage is actually "visible" from on-stage.
> I mean other then beeing different nodes in a referential > fabric? BTW, is there a good name for it? I guess Matrix is also > over-used.
> My view is that Perl6 should have > a name tree, > a type lattice and > a meta graph/model/fabric?
Sure that sound sane. However I am just the meta-model guy, the rest of that list is not my expertise.
>>> and >>> there is multiple inheritance that adds edges into the tree which >>> transform >>> it into a DAG. >> Nothing in an object model is ever a DAG, there are always cycles. >> And MI does not complicate things either, a MetaClass just holds a >> list of superclasses, thats it, nothing more. >>> And I see also classless objects. >> Yes, but those are not going to be handled in the meta-model, because >> the meta-model is all about classes. You can however, build a >> classless system on top of the metamodel, using classes of course.
> Could it be the case that choosing the same terms 'class' and 'object' > on the meta level as on the user level is a *bad* idea? At least it > will be a source of confusion.
What else shall we call them? They really are classes and objects. I do understand your confusion though, it took me a few weeks to get over that in my head.
>> Ahhh, the circularity of it all :)
> What is the benefit of the circularity?
It is the foundation of a reflective object model (reflective being the key word here). Why? I have no real idea, that is just how it is done everywhere I have seen, and I tend to defer to those who are far smarter than I will ever be on things like this.
If you do not have the cycle though, you end up having to implement everything on the meta-side in your runtime, which is partially how the current JS version of the metamodel is implemented. The only thing in that model which is defined in the user-level is Perl6::Object. In the p5 version however, both Perl6::Object and Perl6::MetaClass are actually defined in user-level code. Sure they use a lot of meta-level hooks, but it is really user level code. And since this is user-level code, it means it is user-level manipulatable :)
>> Once you get used it it, it is really a beautiful thing.
> Infinite recursion is a great mental tool, indeed. > But somewhat difficult to implement without either > infinite processing time or infinite memory :)
This is where the bootstrapping comes in. When properly bootstrapped, the model is stable and will not digress into infinite loops. Sure there is some ugliness to account for the bootstrapping as well as some hacks to take care of some meta-circular-stability issues, but all in all, the model holds.
> The associated type > is something like 'direct instance of Foo'. It is > checked with the .does method. This type is then > used as type parameter to constrain one of the Fantastic > Four ($&@%):
> my Foo $foo; # $foo now of type 'Undef of Foo'
> foo = Foo.new; # type correct because Foo.new.does(Foo)
>> ~ class(Foo) ~ >> Used as the invocant of class methods >> => Any other purpose? >> Is an object; instance of the 'Class' class
> From the type system point of view class(Foo) is a Class type. > But that is what bare Foo means anyway if the innermost entry > in the namespace was generated from the class special form.
>> => How do we get properly-typed access to members that class(Foo) >> has >> that aren't declared in 'Class'?
> Sorry, I don't understand that. What do you want to access? > Private class data? Or even lower level implementation details? > Everything else should be accessible through namespace syntax:
> &Foo::action(); # action call through Code ref > $Foo::attr; # data slot access > @Foo::attr[42] # array slot
> given Foo # binds block owner $/ to Foo, $_ from outside > { > &::action(); # &action() etc. work as well > $::attr; > @::attr[42];
> # or with my idea of slot accessor expressions > # bound through $/ := Foo
> &.action(); > $.attr; > @.attr[42];
> # or with method dispatch that does not necessarily > # end up calling a slot in Foo
> my method action # hide OUTER::action > { > say "no Foo method but invocant.does(Foo) is $/.does(Foo)"; > # what would next METHOD call here? > } > # Note that 'my multi method action' would temporarily install > # action in an existing outer multi or create a new local one and > # and install an outer non-multi in it or some such. > # I'm not the dispatch Guru ;)
> .action(); # prints "no Foo method but invocant.does(Foo) is true" > .attr; # MMD could select Foo::Item::attr accessor > .attr[42]; # MMD could select &postfix:<[ ]>(Foo::Array::attr, 42) > }
>> ~ meta(Foo) ~ >> Members contain info /about/ Foo, rather than /of/ Foo >> => This is to avoid name-clashes with 'name', 'authority' etc. >> Is an object; instance of the 'MetaClass' class
> If avoiding name clashes is all, a simple Foo::META pseudo > namespace and %META hash would do. Why a MetaClass and instances of it?
Avoiding name clashes is one point, and I tried the Foo::META thing at one point. Actually the current meta-model grew out of that early prototype, but soon it outgrew that. IIRC it lead to a lot of code duplication, which likely was an implementation detail.
> I hope that .isa, .does and .meta are normal Method subtypes and *not* > slots on some implementation objects/structures.
I am not sure I understand this. Can you elaborate?
On Tue, Aug 09, 2005 at 03:54:23PM -0400, Stevan Little wrote:
: Stuart, : : On Aug 9, 2005, at 9:25 AM, Stuart Cook wrote: : >Stevan, : > : >Up until today, I thought I had a good idea of how your metamodel : >works, but now I'm confused. My main sticking point is that a class : >Foo seems to have three different aspects: : > : >Foo : >class(Foo) : >meta(Foo) : > : >For each of these, could you please try to explain: : >1) Roughly what its responsibility is (and how it relates to the : >others) : >2) Whether it is actually an object : >3) If so, what its class is : : I will simply add to your explanations below (the are mostly correct). : Keep in mind, as I said to TSa, I am coming from a implementation point : of view, and so much of what I descibe will be about the : implementation.
And I will comment from the language point of view.
: >I realise that some of these details are probably spread around : >Synopses, source code, and the inside of your own head, but it would : >really help to have a concise, clear definition of each. : : Yes, sorry. This is why I am trying to document it now. : : > : >So far, this is what I have picked up; some/most of it is probably : >wrong: : > : >~ Foo ~ : >Is a type that variables etc. can be declared to have : : That is one way to look at it I suppose. The reality is that there will : be no actual 'Foo', at least not in the metamodel. 'Foo' is a magical : interpreter concept, which is really just an : alias/pointer/level-of-indirection/whatever for class(Foo).
Well, Perl 6 The Language sees "Foo" as package(Foo), actually.
: This is all, of course, implementation details.
When Perl 6 The Language sees any bare identifier, it cannot treat it as a bareword like Perl 5 does, since Perl 6 has no barewords. So either something in the context tells us what "Foo" means, or it will be taken as a list operator that hasn't been declared yet. There are various "nearby" contextualizers, such as an immediately preceding "sub" or an immediately following "(" or "=>". Distant context basically comes down to declarations that influence the langauge that is recognized at the current location, and a class declaration is just one of those kinds of declaration.
: >Is not an object : : Nope... its magic :)
Well, hmm, except insofar as any package is an object that knows how to be a symbol table, and and be the base class for other kinds of more magical packages. The magic comes into play when these various package objects start pretending to be modules or classes or roles or subtypes.
: > => I'm really not sure about this... : : ahh, but you were correct. Trust your instincts Stuart < the force is : strong with this one I think >
Yes, you're basically correct. It's just that Perl 6 The Language thinks that all types are "interfaces" and thus stored in various kinds of packages, many of which have public names, though there are also anonymous and lexical packages/modules/classes/roles/types.
: >~ class(Foo) ~ : >Used as the invocant of class methods : : Yes. It is also the connection between the concrete instance and : concrete metaclass instance. : : > => Any other purpose? : : In autrijus's version of the model it also stores the index of the : attribute in the instance storage array. But other than that, no it has : no other purpose in my eyes.
From the viewpoint of Perl 6 The Language, a class also serves as the generic placeholder for reasoning about objects of the class in the abstract without necessarily actually having an object of that type to play with. As such it's the logical invocant for constructors, as well as other methods that want to play "what if" games on the objects of the class without necessarily creating one. Some of these abstract games will naturally call into the guts of the metaclass for answers. For example, you might ask the class an abstract question: "If I were to ask each existing object whether it thinks it's a member of your class, how many would say 'yes'?" Of course, the efficient way to answer that question is probably not to interrogate all the objects, but just cheat somehow via the metaobject.
I kinda like Autrijus's idea that "meta" just means "guts". In classical Greek, "meta" just means "with". The fancy philosophical meaning of "aboutness" isn't there, but is a backformation from terms such as metaphysics. Metaphysics is just what you study along "with" physics.
Though "guts" objects is a bit offputting. You know, I keep mistyping "meta" as "meat" half the time, so maybe we should make that a feature and call them "meat" objects instead. :-)
Except that then I'd be typing "meat" as "meta" half the time...
: >Is an object; instance of the 'Class' class : : Perl6::Class in the p5 metamodel. I also find adding either the Perl6:: : or just :: at the front of names like 'Class' are helpful. : : > => How do we get properly-typed access to members that class(Foo) has : > that aren't declared in 'Class'? : : class(Foo) instance methods will be for 'Foo', and the class methods : will be for ::Class. : : The current metamodel hacks this in a kind of ugly way, but that is how : I am seeing it.
I'm not sure if Class is really a class or just a role containing the interface to bootstrap a class instance using the meatclass, er, I mean, the metaclass. The abstract parts of a class that overlie the package are rather, um, abstract.
> : >So far, this is what I have picked up; some/most of it is probably > : >wrong: > : > > : >~ Foo ~ > : >Is a type that variables etc. can be declared to have > : > : That is one way to look at it I suppose. The reality is that there > will > : be no actual 'Foo', at least not in the metamodel. 'Foo' is a magical > : interpreter concept, which is really just an > : alias/pointer/level-of-indirection/whatever for class(Foo).
> Well, Perl 6 The Language sees "Foo" as package(Foo), actually.
IIRC, autrijus said that one of the base concepts in PIL was a namespace (which is roughly equivalent to a package). So I have assumed in my metamodel (and mostly in recent refactorings) that the magic behind "Foo" would have something to do with packages/namespaces. So this aligns nicely with your view.
> : >Is not an object > : > : Nope... its magic :)
> Well, hmm, except insofar as any package is an object that knows how > to be a symbol table, and and be the base class for other kinds of more > magical packages. The magic comes into play when these various package > objects start pretending to be modules or classes or roles or subtypes.
Let me make sure I understand this.
Package is an Object. Module is a Package. Class is a Package. Role is a Package.
(I wont even go near subtypes as I dont completely understand them).
But is Perl6::Class (the Class class) also a Package? Or is "Foo" the Package in this picture?
If "Foo" is the Package, then it would then be possible to implement this system on-top of the metamodel?
If Perl6::Class is also a package, then we have a potential bootstrap issue.
> : > => I'm really not sure about this... > : > : ahh, but you were correct. Trust your instincts Stuart < the force is > : strong with this one I think >
> Yes, you're basically correct. It's just that Perl 6 The Language > thinks that all types are "interfaces" and thus stored in various > kinds of packages, many of which have public names, though there > are also anonymous and lexical packages/modules/classes/roles/types.
> : >~ class(Foo) ~ > : >Used as the invocant of class methods > : > : Yes. It is also the connection between the concrete instance and > : concrete metaclass instance. > : > : > => Any other purpose? > : > : In autrijus's version of the model it also stores the index of the > : attribute in the instance storage array. But other than that, no it > has > : no other purpose in my eyes.
>> From the viewpoint of Perl 6 The Language, a class also serves as the > generic placeholder for reasoning about objects of the class in the > abstract without necessarily actually having an object of that type > to play with. As such it's the logical invocant for constructors, as > well as other methods that want to play "what if" games on the objects > of the class without necessarily creating one. Some of these abstract > games will naturally call into the guts of the metaclass for answers. > For example, you might ask the class an abstract question: "If I were > to ask each existing object whether it thinks it's a member of your > class, how many would say 'yes'?" Of course, the efficient way to > answer that question is probably not to interrogate all the objects, > but just cheat somehow via the metaobject.
I see all these "methods of interrogation" as being class methods defined in the base Object. Would that be correct?
> I kinda like Autrijus's idea that "meta" just means "guts". In > classical Greek, "meta" just means "with". The fancy philosophical > meaning of "aboutness" isn't there, but is a backformation from > terms such as metaphysics. Metaphysics is just what you study along > "with" physics. > Though "guts" objects is a bit offputting. You know, I keep mistyping > "meta" as "meat" half the time, so maybe we should make that a feature > and call them "meat" objects instead. :-)
> Except that then I'd be typing "meat" as "meta" half the time...
GutClass is kinda gross. I personally like the metaphors in "The Art of MOP", which are backstage objects/classes and on-stage objects/classes. The only thing that seperates them is the curtain, and even that can be pulled away to expose more, but is always in control of the backstage "crew" (aka the language implementors).
> : >Is an object; instance of the 'Class' class > : > : Perl6::Class in the p5 metamodel. I also find adding either the > Perl6:: > : or just :: at the front of names like 'Class' are helpful. > : > : > => How do we get properly-typed access to members that class(Foo) > has > : > that aren't declared in 'Class'? > : > : class(Foo) instance methods will be for 'Foo', and the class methods > : will be for ::Class. > : > : The current metamodel hacks this in a kind of ugly way, but that is > how > : I am seeing it.
> I'm not sure if Class is really a class or just a role containing > the interface to bootstrap a class instance using the meatclass, er, > I mean, the metaclass. The abstract parts of a class that overlie > the package are rather, um, abstract.
On Wed, Aug 10, 2005 at 10:47:47AM +0200, Juerd wrote: > Larry Wall skribis 2005-08-09 16:19 (-0700): > > So either something in the context tells us what "Foo" means, or > > it will be taken as a list operator that hasn't been declared yet.
> Is there, by the way, a pragma to force predeclaration of subs, to gain > compile time typo checking?
Actually, "use optimize :package<closed>" effectively does that.
But it's an toplevel optimization, which is not applicable to module authors. So I'd very much welcome a lexical pragma that forces static binding of subroutine calls.
Preferably we can use the same pragma can handle methods as well. Something like:
On 8/10/05, Autrijus Tang <autri...@autrijus.org> wrote:
> But it's an toplevel optimization, which is not applicable to > module authors. So I'd very much welcome a lexical pragma that > forces static binding of subroutine calls.
Yeah, but the whole point of not allowing that is so that you can override modules when you need to. However, I think the toplevel closed requirement might be a little too harsh. After all, you could just say:
use dynamic 'Foo';
Or something, to unforce that on a module's behalf. That declaration should probably not load the module for you, so that you can force dynamicity on modules that other modules use.
use dynamic;
Would force every module to be dynamic, and should probably only be allowed at the top level.
In summary: You're allowed to say "I don't do funny stuff to myself", and someone else is allowed to say "but I do funny stuff to you".
The only thing I see as problematic is a module that knows it's evil and has to "use dynamic". The module could request that the user of the module "use dynamic", so that people know when they're using a module that will slow everything down. The other way is to hack around it using something like a source filter, pretending that the user of the module actually did write that. But that's not $&, because it's quite a bit more difficult to do. If you encapsulate that difficulty into a module, that module will eventually be shunned by the speed-centric part of the community.
On Wed, Aug 10, 2005 at 06:03:18AM -0600, Luke Palmer wrote: > On 8/10/05, Autrijus Tang <autri...@autrijus.org> wrote: > > But it's an toplevel optimization, which is not applicable to > > module authors. So I'd very much welcome a lexical pragma that > > forces static binding of subroutine calls.
> Yeah, but the whole point of not allowing that is so that you can > override modules when you need to.
No. A lexical static binding pragma controls the function I _call_; the outlawed "is final / is closed" is to control the functions I _define_.
Also, runtime rebinding of the actual function I call is always possible, provided that it's rebound to something of compatible type.
you wrote: >> I hope that .isa, .does and .meta are normal Method subtypes and *not* >> slots on some implementation objects/structures.
> I am not sure I understand this. Can you elaborate?
With pleasure!
OK, where do I start? ...
The origin of OO stems from the need to organize data structures and code that deals with them in a way that prevents glitches. The idea is to somehow put the functions into the data. This is the syntactical idea in the most prominent OO-languages Java and C++. Typical implementaion is through pointer tables that the instances carry around. This approach breaks down when it comes to multi methods.
Type theory started from the other end. Actually, since data manipulation is difficult to model there where only pure functions or lambda expressions and their application. A type system starts out with primitive types and then introduces so-called arrow types or function types written in Perl6 as :( ::A --> ::B ) these days.
With first-class functions or closures the question arises "when is an arrow type a subtype of another?". This question is answered differently for Subs and Methods! For subs the ::A of the subtype has to be a *supertype* of the ::A of the supertype. In plain english a function has to accept a wider or equal range of types if it shall replace another. For methods the invocant part of ::A goes with the outer subtype relation of the methods. The rest works as with subs. After the most specific method from a set of applicable ones is selected it can be bound to or curried on the invocant and temporarily becomes a sub. This binding of the invocants is called single or multiple dispatch depending on the arity of the invocant type. BUT it is *no* lookup inside the invocant!
To summarise: a free method just states its required type of invocants that it can handle and the dispatcher ensures two things: 1) that the invocant type matches 2) that the most specific method in scope is bound to it This implies that you can taylor an invocant if you know the constraints. Classes and roles are a very convenient means to automate this tayloring. As such they are a very powerfull implementation device.
BTW, the above also explains my difficulties with Damians metric dispatch because you can decide if ::A.does(::B) but defining a measure from how far away ::A does that is beyond me.
Coming back to .isa, .does and .meta I just wanted to say that I hope they are not implemented as slots on some data structure of your meta model but as self-contained parts of Perl6 The Language.
Here is an example of a 2D distance method
role Point { has Num $.x; has Num $.y; } method distance( Point $a, Point $b --> Num ) { return sqrt( ($a.x - $b.x)**2 - ($a.y - $b.y)**2); }
Now comes the not-yet-Perl6 part:
Complex does Point where { $.x := $.real; $.y := $.imag }
Array[Num] does Point where { $.size >= 2 or fail; $.x := @.values[0]; $y := @.values[1] }
a hash might just work with the right keys and value types
my %g = { x => 2.4, y => 3.14 }; # %g.does(Point) is true my %h = { x => 0.8, y => 1.22 };
say distance( %g, %h );
my @a = (0, 3);
my Complex $c = (4,3);
say distance( @a, $c ); say distance( %h, @a ); say distance( (0,3), (2,6) ); # works if List.does(Array) say distance( [1,1], [2,4] ); # works because Ref[Array].does(Array) say distance( $c, [0,1,2,3] ); # works because [0,1,2,3].does([0,1]) # etc. -- $TSa.greeting := "HaloO"; # mind the echo!
On 8/10/05, TSa <Thomas.Sandl...@orthogon.com> wrote:
> Here is an example of a 2D distance method
> role Point > { > has Num $.x; > has Num $.y; > } > method distance( Point $a, Point $b --> Num ) > { > return sqrt( ($a.x - $b.x)**2 - ($a.y - $b.y)**2); > }
> Now comes the not-yet-Perl6 part:
I wouldn't say that...
> Complex does Point where { $.x := $.real; $.y := $.imag }
use self './';
Complex does role { does Point; method x () is rw { ./real } method y () is rw { ./imag }
} > Array[Num] does Point > where { $.size >= 2 or fail; > $.x := @.values[0]; $y := @.values[1] }
# This one is quite a bit more dubious than the last Array[Num] where { .elems >= 2 } does role { does Point; method x () is rw { ./[0] } method y () is rw { ./[1] }
}
That subtype would have to be an "auto-subtype", that is, it would have to know that it is a member of that type without being told so. Such subtypes can introduce major inefficiencies in the program, and are best left either out of the language, or somewhere in the dark depths of I-know-what-I'm-doing-land.
Luke Palmer wrote: > On 8/10/05, TSa <Thomas.Sandl...@orthogon.com> wrote:
>>Here is an example of a 2D distance method
>> role Point >> { >> has Num $.x; >> has Num $.y; >> } >> method distance( Point $a, Point $b --> Num ) >> { >> return sqrt( ($a.x - $b.x)**2 - ($a.y - $b.y)**2); >> } [..] > # This one is quite a bit more dubious than the last > Array[Num] where { .elems >= 2 } does role { > does Point; > method x () is rw { ./[0] } > method y () is rw { ./[1] } > }
> That subtype would have to be an "auto-subtype", that is, it would > have to know that it is a member of that type without being told so.
Sorry, I do not regard it as dubious. It perfectly illustrates my point that every instance/object/entity can qualify for an arbitrary number of types because it is the types who define what belongs to them and what not. What makes (2**31 - 1) a prime number? And what excludes it from evenness? Is it a Fibonacci number? Is it a Complex? Or an Octonion? Who has made Badgad a member of the AxisOfTheEvil and bound it as invocant to a self declared .rescue method?
Don't get me wrong. My last question there is just for provoking emotions. I'm making no judgement. That is left to a far more powerfull entity than me on hmm, $day.does(Judgement) :) And don't ask me to which point in spacetime $day is bound!
> Such subtypes can introduce major inefficiencies in the program, and > are best left either out of the language, or somewhere in the dark > depths of I-know-what-I'm-doing-land.
I claim the opposite. My distance method exists in namespace like any other code object. When it comes to creating an invocation of it the prospective invocants are already at Hand. So, no efficiency penalty, yet. The applicability check is based on type information stored under ::distance and is at hand already and there are far more complicated tests than an Array subtype check, an Array content type check combined with a size check. The binding of two references per Point will hardly constitute a problem either. And don't tell me that the potentially lazy calculation, optimization and caching under ::distance of such an applicability closure is beyond the capabilities of Parrot/Perl6.
For multi methods the above procedure will be carried out for all potential targets of the invocation and nobody has complained about inefficiencies there, yet. At least not about others than the ones that inherently come with MMD itself. -- $TSa.greeting := "HaloO"; # mind the echo!
On Wed, Aug 10, 2005 at 10:12:45AM -0700, Larry Wall wrote: > We can get away with this in Perl 6 because bindings to positionals > happen lazily. So all we have to check for syntactically is that we > don't have a subsequent declaration that changes the syntax from list > to unary (or none-ary).
On Wed, Aug 10, 2005 at 10:47:47AM +0200, Juerd wrote:
: Larry Wall skribis 2005-08-09 16:19 (-0700): : > So either something in the context tells us what "Foo" means, or : > it will be taken as a list operator that hasn't been declared yet. : : Is there, by the way, a pragma to force predeclaration of subs, to gain : compile time typo checking?
You get compile time checking of those anyway--it's just deferred a bit. The undeclared list operator must be declared by the end of this compilation unit or it's an error. (We should probably say the same for parenthesized calls.) However, the visibility of an autoloader turns off this compile-time error checking.
We can get away with this in Perl 6 because bindings to positionals happen lazily. So all we have to check for syntactically is that we don't have a subsequent declaration that changes the syntax from list to unary (or none-ary).
In the case of multi subs, there just has to be at least one declaration visible by the end of the current compilation unit. Since most such declarations will be made visible by "use" anyway, it doesn't seem like a big problem. At worst we might need a stub syntax to declare that something is to be forced (like a class forcing role methods to be multi) without declaring one of the actual multis. So
multi foo {...}
says that short name "foo" will eventually be a set of multies.
It would still be possible to have a pragma that forces predeclaration, of course. And lexically scoped subs always have to be predeclared. You can't call a lexically scoped sub whose first "my" declaration is after the call.
Hmm. Does that mean that lexical stubs/subs are declared/defined like this:
my sub foo {...} my sub foo { say "I'm real now" }
or like this:
my sub foo {...} sub foo { say "I'm real now" }
The former seems cleaner somehow, except that it also implies that multiple "my $x" are declaring the same $x. I can see arguments for both sides. If &foo is just short for "sub foo", then the second form should work just fine. But people might prefer to my-ify the second form just to document that it's not a package sub, and maybe that should be allowed.
TSa <Thomas.Sandl...@orthogon.com> wrote: > you wrote: > > Perl 6 in its unannotated form is also (mostly) a typeless languages, > > with only the five builtin types, much like Perl 5 is.
> Counting the sigil quadriga as 4, what is the fifth element? > And $it.does(LookGood)?
$ @ % & ::
-- Brent 'Dax' Royal-Gordon <br...@brentdax.com> Perl and Parrot hacker
On Wed, Aug 10, 2005 at 07:32:01PM +0200, TSa wrote: > you wrote: > >Perl 6 in its unannotated form is also (mostly) a typeless languages, > >with only the five builtin types, much like Perl 5 is.
> Counting the sigil quadriga as 4, what is the fifth element?