Re: Re: class interface of roles
On 10/6/06, TSa [EMAIL PROTECTED] wrote: HaloO, Stevan Little wrote: As for how the example in the OP might work, I would suspect that super would not be what we are looking for here, but instead a variant of next METHOD. I'm not familiar with the next METHOD syntax. How does one get the return value from it and how are parameters passed? Would the respective line in the equal method then read: return next METHOD($p) and self.x == $p.x and self.y == $p.y; I think that a super keyword might be nice syntactic sugar for this. I think super is not something we would want in Roles, it implies ordering, which defeats the flattening aspect of Roles. IIRC the syntax to call the next method with new args and a return value is this: return call($p) and self.x == $p.x and self.y == $p.y; However, I am not sure I really like the look of that myself. However, even with that an ordering of some kind is implied The only ordering I see is that the class is up from the role's perspective. But thats the whole problem, there is no up in roles, they are flattened. When more then one role is combined and all require the presence of an equal method I think the roles can be combined in any order and the super refers to the class combined so far. IOW, at any given time in the composition process there is a current version of the class' method. The final outcome is a method WALK or however this is called in composition order. Conceptually this is method combination: seen from outside the class has just one type correct method equal. Theoretical background can be found in http://www.jot.fm/issues/issue_2004_01/column4 I do not think method combination should be the default for role composition, it would defeat the composeability of roles because you would never have conflicts. However, I can see the possibility of method combinations in roles being some kind of special case. How that might look from a syntactic perspective I have no idea. I suppose this is again where the different concepts of classes are roles can get very sticky. I have always look at roles, once composed into the class, as no longer needing to exist. In fact, if it weren't for the idea of runtime role compostion and runtime role introspection, I would say that roles themselves could be garbage collected at the end of the compile time cycle. I see that quite different: roles are the primary carrier of type information! Well yes, they do seem to have taken on this role ;). However, roles as originally envisioned in the Traits paper are not related to the type system, but instead related to class/object system. In fact the Trait paper gave it's examples in Smalltalk, which is not a strongly typed language (unless you count the idea that *everything* is an object and therefore that is their type). I think we need to be careful in how we associate roles with the type system and how we assocaite them with the object system. I worry that they will end up with conflicting needs and responsibilities and roles will end up being too complex to be truely useful. Dispatch depends on a partial ordering of roles. Type based dispatch does (MMD), but class based method dispatch doesn't need it at all. The whole fact that dispatching requires roles to be partially ordered actually tells me that maybe roles should not be so hinged to the type system since roles are meant to be unordered. Possiblely we should be seeing roles as a way of *implementing* the types, and not as a core component of the type system itself? I did some experimentation with this in Moose::Autobox, but that is for Perl 5 so I am not sure how relevant it is here. - Stevan
Re: Re: class interface of roles
On 10/6/06, TSa [EMAIL PROTECTED] wrote: HaloO, Stevan Little wrote: On 10/2/06, Jonathan Lang [EMAIL PROTECTED] wrote: This notion of exclusionary roles is an interesting one, though. I'd like to hear about what kinds of situations would find this notion useful; but for the moment, I'll take your word that such situations exist and go from there. Well to be honest, I haven't found a real-world usage for it yet (at least in my travels so far), but the Fortress example was this: trait OrganicMolecule extends Molecule excludes { InorganicMolecule } end trait InorganicMolecule extends Molecule end Wouldn't that be written in Perl6 the other way around? role OrganicMolecule {...} role InorganicMolecule {...} role Molecule does OrganicMolecule ^ InorganicMolecule {...} Which is a nice usage of the xor role combinator. Well, it does seem to accomplish a similar goal. However, in your example there is nothing about the OrganicMolecule which will prevent me from composing it with the InOrganicMolecule, which was the primary goal of the Fortress example. In addition in the Fortress example the Molecule role is not coupled to the Organic and Inorganic molecules, in your example they are. But IMHO this is just another example of TIMTOWTDI, because your example achieves similar goals and would likely be a valid design approach as well. And from that I could see that given a large enough set of roles you would surely create roles which conflicted with one another on a conceptual level rather then on a methods/attribute (i.e. - more concrete) level. I don't abide to that. If roles are conceptually modelling the same entity their vocabulary should conflict also. Well unless some differing coding conventions accidentally produce non-conflicting roles. The whole point of type systems relies on the fact that concrete conflicts indicate conceptual ones! But part of the power of role composability is that the role itself does not need to dictate what class it is composed into. So conceptual conflicts cannot be determined until compostion actually occurs, and conflicts between two conceptually conflicting roles cannot be detected until composition time either. And of course there is nothing to say that two conceptually conflicting roles have a concrete conflict either (either between methods or attributes). I think that maybe we need to seperate the concept of roles as types and roles as partial classes, they seem to me to be in conflict with one another. And even they are not in conflict with one another, I worry they will bloat the complexity of roles usage. My experiences thus far with roles in Moose have been that they can be a really powerful means of reuse. I point you towards Yuval Kogman's latest work on Class::Workflow, which is basically a loose set of roles which can be composed into a highly customizable workflow system. This is where I see the real power of roles coming into play. - Stevan
Re: Re: class interface of roles
On 10/2/06, Brad Bowman [EMAIL PROTECTED] wrote: Sam Vilain wrote: TSa wrote: is this subject not of interest? I just wanted to start a discussion about the class composition process and how a role designer can require the class to provide an equal method and then augment it to achieve the correct behavior. Contrast that with the need to do the same in every class that gets the equal method composed into if the role doesn't have a superclass interface as described in the article. This will be the same as requiring that a class implements a method, except the method's name is infix:==(::T $self: T $other) or some such. How does a Role require that the target class implement a method (or do another Role)? IIRC, it simply needs to provide a method stub, like so: method bar { ... } This will tell the class composer that this method must be created before everything is finished. Does the class GenSquare does GenEqual does GenPointMixin line imply an ordering of class composition? This would seem to be required for the super.equal hand-wave to work but part of the Traits Paper goodness came from avoiding an ordering. Composition is just order insensitive flattening. Conflicts like the equal method in the OP have to be explicitly resolved in the target class, either using aliases or fully qualified names. So there's no super needed. The super in a Role should be late bound, so will have no relevance when inside the role, but only make sense when composed into a class. This is probably one of the more confusing points of roles I think. As for how the example in the OP might work, I would suspect that super would not be what we are looking for here, but instead a variant of next METHOD. However, even with that an ordering of some kind is implied. I suppose this is again where the different concepts of classes are roles can get very sticky. I have always look at roles, once composed into the class, as no longer needing to exist. In fact, if it weren't for the idea of runtime role compostion and runtime role introspection, I would say that roles themselves could be garbage collected at the end of the compile time cycle. I would like a way to make one Role to require that the target class does another abstract Role, is there already such a technique? I am not familiar with one, but I have had this need as well lately in using Moose roles. We have a concept in Moose (stolen from the Fortress language) where a particular role can exclude the use of another role, but not the ability to require it, although I see no reason why it couldn't be done. - Stevan
Re: Re: Re: class interface of roles
On 10/2/06, Jonathan Lang [EMAIL PROTECTED] wrote: This notion of exclusionary roles is an interesting one, though. I'd like to hear about what kinds of situations would find this notion useful; but for the moment, I'll take your word that such situations exist and go from there. Well to be honest, I haven't found a real-world usage for it yet (at least in my travels so far), but the Fortress example was this: trait OrganicMolecule extends Molecule excludes { InorganicMolecule } end trait InorganicMolecule extends Molecule end And from that I could see that given a large enough set of roles you would surely create roles which conflicted with one another on a conceptual level rather then on a methods/attribute (i.e. - more concrete) level. - Stevan
Module/Class Authoritys
Quick question for the group. Can there be more than one authority? module Foo-0.0.1-cpan:JRANDOM-http://www.foo.org-mailto:[EMAIL PROTECTED] S11 would seem to indicate no (it states that names are made up of 3 parts), but I guess I am wondering if one of those parts can have multiple sub-parts in it? Thanks, - Stevan
Re: packages vs. classes
On 5/23/06, Sam Vilain [EMAIL PROTECTED] wrote: Right, but we should really ship with at least a set of Meta Object Protocol Roles, that covers the core requirements that we will need for expressing the core types in terms of themselves; - classes and roles - attributes and methods - subsets (ie constraints/subtypes) - generics (including, by induction, nested generics) I *think*, at this point, that's all that are necessary. I would maybe add a protocol for instance creation. We have recently added that to Moose, and found it very useful in terms of abstracting out the kind of instance storage used (ARRAY based storage currently Just Works given the right Instance sub(meta)class). I see the instance protocol as being an important component of cross language runtime thing. If all instances conform to, or can be made to conform to, an base instance protocol, making Perl 6 objects which inherit from Python objects should be fairly easy. People can instantiate the roles that cover all that to an actual metaclass in whatever way they like (eg, Moose::Meta::Class-isa(Class::MOP::Class)), but not having to detect the type and then figure out how to talk to it for at least the core of the object system would be good. I think the roles can serve as the core interface nessecary to function with the base object system. As long as my metaclass .does() the correct role, it should be able to function in the object system. Of course the old garbage-in garbage-out rule applies, we should give you enough meta-rope to shoot your meta-self in your meta-foot. People can diverge completely with completely incompatible metaclasses that don't .do those roles, the only side effect of which being that people who write code for the standard Perl 6 metamodel will be incompatible, and maybe some ways of setting up the class won't work without another layer of trickery. I *think* that's what you're getting at. Of course, it shouldn't be prohibited just because it smells. I am not sure I like this, incompatible metaclass issues are really really tricky and hard to debug (aka - smells *really* bad). And the system needed to support them really can bloat the metamodel internals in a nasty way. There are several papers out there on the subject, none of which IMO provide a satisfactory solution. The problem then becomes compounded by introducing the Python and Ruby metamodels into the fray. Having a single compatability level made out of roles is not that much of a restriction really, and keeps much of the system interals clean and orderly. It also makes it much easier for use to add new metamodels from other languages by just by writing a layer to map to the core metamodel roles. - Stevan
Re: Perl 6 design wiki?
On 3/5/06, Mark Overmeer [EMAIL PROTECTED] wrote: * Stevan Little ([EMAIL PROTECTED]) [060305 02:49]: On 3/4/06, Mark Overmeer [EMAIL PROTECTED] wrote: Could we try to kind-of pre-register name-spaces for perl6 modules? There is no need to do such a thing, we have the 3 level naming scheme in Perl 6 now. Foo-0.0.1-cpan:JRANDOM I know about the naming scheme, but I am not really looking forward to the two new perl books Perl DBI-(Any)-cpan:TIMB and Perl DBI-(Any)-mailto:[EMAIL PROTECTED] That you have the possibility to work your way out in namespace clashes shouldn't directly mean that you let them happen easily. I would really like to maintain a certain hierarchical name-space structure on CPAN, where we strive for unique names, although can work around accidental collissions. I agree completely, and to be honest, I think the three level namespace will be more useful in the context of a single company and/or application, and be used more for versioning that anything else. An other reason to have a kind of module/namespace pre-registration is to see who is (planning to go) working on what. I think that's needed on the moment. Well, to start with, there is no C6PAN/SixPan/Whatever-it-will-be-called yet, so there is nothing to pre-register for. Second, Perl 6 is still (at the very least) a year away from a (mostly) complete implementation, and that most likely will not be the official one, and only a reference implementation that very few people (read: audrey) will actually use in production. The official version with Parrot and Ponie and few enough bugs to call 6.0.0 is maybe a few years out from that. So pre-registration for namespaces in an unfinished language is a litte premature IMO. And lastly, I really don't like the idea anyway. It reminds me of the domain-name squatters of the mid-90s. Just because I (with my best intentions intact) decide that I want to write World::Domination::Simple in 2006, does not mean that someone else in 2008+ should have to come up with another name because I registered for the namespace I never used (and am unwilling to give up). In addition, while I agree with you that there is some Perl 4/5 cruft in CPAN that really should be tossed, this ignores the legacy apps that might still need to use this code. And as for stealing the good namespaces for writing new (and surely better) but very different Perl 6 modules, I am not actually sure I like that. Of course if the dream of Parrot/Ponie really works 100%, then it will probably be a non-issue, but if it doesn't (and there is yet to be a clear plan layed out as to how we will bridge Perl 5 - 6), then updating legacy modules to Perl 6 might be something which really needs to happen if people are going to be able to port their larger Perl 5 code within a reasonable amount of time and effort. This is especailly true for modules like File::Spec or Test::More, which so many other modules just use as if they are part of the language. I don't mind re-working my core module to use the new whiz-bang OO features, but I would prefer to be able to automatically (and mechanically) convert my test suite rather than have to covert to some type off xUnit style tests or something. Some things may just need to stay the same, namespace intact. Anything else would IMO further the Perl 5/6 gap that will inevitably exist because of the depths of the language changes. - Stevan
Re: Perl 6 design wiki?
On 3/4/06, Mark Overmeer [EMAIL PROTECTED] wrote: One thing which is playing in my head already for some time is: Do we really want a translation from Perl5 modules into Perl6 on a one-to-one basis? There are so many deceased modules occupying beautiful name-spaces! Can we please re-arrange the name-spaces? Could we try to kind-of pre-register name-spaces for perl6 modules? There is no need to do such a thing, we have the 3 level naming scheme in Perl 6 now. Foo-0.0.1-cpan:JRANDOM - Stevan
Re: Multisubs and multimethods: what's the difference?
On 3/2/06, Jonathan Lang [EMAIL PROTECTED] wrote: Can subs be declared within classes? Can methods be declared without classes? If the answers to both of these questions are no, then it occurs to me that you _could_ unify the two under a single name, using the class boundary as the distinguishing factor (e.g., a method is merely a sub declared within a class). If the answer to either is yes, I'd be curious to know how it would work. I would say yes. Having subs inside classes makes creating small utility functions easier. You could also use private methods for this, but if I dont need to pass the object instance, why make me? I will say that I think this distinction will be difficult at first for people steeped in Perl 5 OO. Having methods outside of classes is less useful, and most of it's uses are pretty esoteric, however I see no good reason not to allow it (especially anon methods, as they are critical to being able to do some of the cooler meta-model stuff). A method probably cannot be invoked without first being attached to a class somehow because it needs something to SMD off of. But you could almost look at a bare (and named) method as a mini-role, so that: method unattached_method ($::CLASS $self:) { ... } is essentially equivalent to this: role unattached_method { method unattached_method ($::CLASS $self:) { ... } } which of course brings up the possibility of this syntax: $object does unattached_method; ^Object does unattached_method; as a means of adding methods to a class or object (ruby-style singleton methods). Of course, this could also just be my not-quite-caffinated-enough brain talking too. Stevan
Re: Multisubs and multimethods: what's the difference?
On 3/2/06, Jonathan Lang [EMAIL PROTECTED] wrote: Stevan Little wrote: Jonathan Lang wrote: Can subs be declared within classes? Can methods be declared without classes? I would say yes. Having subs inside classes makes creating small utility functions easier. You could also use private methods for this, but if I dont need to pass the object instance, why make me? I will say that I think this distinction will be difficult at first for people steeped in Perl 5 OO. Sounds reasonable. I'm curious: can anyone think of any _public_ uses for subs that are declared within classes? Same uses they would have in Perl 5 I would guess, but I don't usually do that in Perl 5 so I am hard pressed to come up with a specific example. Having methods outside of classes is less useful, and most of it's uses are pretty esoteric, however I see no good reason not to allow it (especially anon methods, as they are critical to being able to do some of the cooler meta-model stuff). OK; so declaring a method outside of a class could let you define one method that applies to a wide range of classes, without having to declare a separate method for each class. I can see how that might come in handy. A method probably cannot be invoked without first being attached to a class somehow because it needs something to SMD off of. Why not? IIRC, SMD differs from MMD dispatch-wise in terms of how many of its parameters are used (one instead of all). If I were to define method foo(Complex $bar) and multi foo(Num $bar), I could then say foo i and expect to be dispatched to the method; whereas foo e would dispatch to the sub. Likewise, i.foo would dispatch to the method, while e.foo would die due to improper syntax. I suppose this is all in the details of how we do SMD. It's things like this that make me think that SMD is just a special case of MMD, but I think that dead horse has already been beaten here, and I am not in the mood to reanimate it really. At least, that's how I see it. What's the official position on what happens when you mix SMD, MMD, and/or no dispatch versions of a routine? But you could almost look at a bare (and named) method as a mini-role, so that: method unattached_method ($::CLASS $self:) { ... } is essentially equivalent to this: role unattached_method { method unattached_method ($::CLASS $self:) { ... } } which of course brings up the possibility of this syntax: $object does unattached_method; ^Object does unattached_method; (Wouldn't that be ^$object does unattached_method;?) No, I am attaching the method (well role really) to the class ^Object. There is no such thing as ^$object IIRC. as a means of adding methods to a class or object (ruby-style singleton methods). Hmm: I don't see a need for this with respect to adding methods to a class; just declare a method that takes a first parameter of the appropriate class. OTOH, TIMTOWTDI: I could see arguments for allowing ^$object does method foo() { ... } as well. OTGH, adding methods to an individual object would pretty much require the use of an anonymous role. So the idea that does wraps bare methods in an anonymous role does seem to have merit. exactly the conclusions I came too as well, which is one of the reason why I really like hanging out on this mailing list :) - Stevan
Re: Instance attributes collision
On 2/15/06, Rob Kinyon [EMAIL PROTECTED] wrote: On 2/14/06, Stevan Little [EMAIL PROTECTED] wrote: I think that the metaclass (stored in the pseudo-lexical $::CLASS) should create a number of anonymous roles on the fly: role { multi method a (::CLASS $self) { ... } multi method a (::CLASS $self, Scalar $value) { ... } } role { multi method a (::CLASS $self) { ... } multi method a (::CLASS $self, Array @value) { ... } } These roles would then be added to the metaclass using the normal rules of role composition. (NOTE: I assume that ::CLASS is unbound until the role is composed into a class, I think A12 might have stated this detail) Now obviously we have a conflict in our multi-methods. S12 only states that multi methods will be compared by their long names (name + signature) to resolve ambiguity, it does not state what happens when those long names conflict. I propose that they work just as normal method conflicts do, which is that both methods are excluded and the consuming class is then required to implement that method. Is it just the first multimethod a(::CLASS $self) from each role being excluded or are all the multimethod a(...)'s being excluded? I would think it could be the first one only, the one where the long name conflicts. Stevan
Re: Instance attributes collision
On 2/12/06, Yiyi Hu [EMAIL PROTECTED] wrote: For perl 6, Array and Scalar are in different namespace. So, class A { has $.a; has @.a }; what will A.new.a return by default? An Error? or Scalar has a higher priority? It seems to me that the best way to approach this issue is to seperate the accessor generation from the attribute declaration. To start with, in Perl 5, it is entirely possible to do this without ambiguity: package Foo; our $bar; our @bar; This is because '$bar' and '@bar' are different names. Perl 6 should follow this, and store the meta-objects which represent these attributes using different names as well, so given: class A { has $.a; has @.a }; You would find two attribute meta-objects, one keyed to '$.a' and the other to '@.a', and there is no ambiguity. Now for the accessor generation portion of this question. Accessor generation should probably take place towards the end of class construction. You need to think of class construction as a multi-step process, first the name is encountered: class A; At this point a metaclass should be created and named A. Next the body of the class should be evaluated within the context of the metaclass. As each attribute declaration is encountered, it should be converted to metaclass calls to further construct the class. So things like this: has $.a; Will translate to something like this: $::CLASS.add_attribute(Perl6::Meta::Attribute.new(:name$.a)); Now, when the classes body has been completely evaluated, a method should be called on the metaclass (found in the $::CLASS pseudo-lexical variable) to tell the metaclass that that class construction has been finished. This method should finish up the class construction and at this point the attribute accessors should now be generated. Now, here is my proposal for how accessor generation should be handled. I think that the metaclass (stored in the pseudo-lexical $::CLASS) should create a number of anonymous roles on the fly: role { multi method a (::CLASS $self) { ... } multi method a (::CLASS $self, Scalar $value) { ... } } role { multi method a (::CLASS $self) { ... } multi method a (::CLASS $self, Array @value) { ... } } These roles would then be added to the metaclass using the normal rules of role composition. (NOTE: I assume that ::CLASS is unbound until the role is composed into a class, I think A12 might have stated this detail) Now obviously we have a conflict in our multi-methods. S12 only states that multi methods will be compared by their long names (name + signature) to resolve ambiguity, it does not state what happens when those long names conflict. I propose that they work just as normal method conflicts do, which is that both methods are excluded and the consuming class is then required to implement that method. So now, if we follow the rules of role composition, when these two anonymous roles are added to the metaclass, there will be a conflict and class composition will fail. So the short answer is that this: class A { has $.a; has @.a }; will result in a fatal compile time error, while this: class A { has $.a; has @.a multi a ($::CLASS) { # do something here,.. I dont know what :) } }; will not fail. Hope this helps :) Stevan
Re: overloading the variable declaration process
On 2/12/06, Thomas Sandlass [EMAIL PROTECTED] wrote: IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. Yes, the question of ownership of methods is still somewhat unresolved. I think we need to distinguish something I've called slots in an object from free (multi) methods that are defined outside of the class definition block. BTW, do the outsiders have access to the private data slots with the $! twigil? I think that multimethods defined outside of the scope of the class should not have access to the classes data slots, it should use the accessors. And those multimethods should live in the package in which they are defined. The class implementation can stash refs to multimethods which apply to it for optimization reasons, but this has nothing to do with the language design itself. As far as method name disambiguation, we should use the calling style (invocant vs. normal function call) to determine which method to call. I am sure there are other edge cases to be uncovered here as well, but I can't think of them at the moment. Stevan
Re: overloading the variable declaration process
On 2/8/06, Jonathan Lang [EMAIL PROTECTED] wrote: Stevan Little wrote: Yes, that is correct, because: Dog.isa(Dog) # true $spot.isa(Dog) # true ^Dog.isa(Dog) # false In fact ^Dog isa MetaClass (or Class whatever you want to call it). At least that is how I see/understand it. OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? Well, a metaclass describes the behaviors and attributes of a class, and ^Dog is an *instance* of the metaclass. So actually ^Dog would not actually have attributes and methods since it is an instance. That said, I think ^Dog would probably respond to methods like these (some of which are described in S12): ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL I would like to see some methods like this: # dynamically add a method that # Dog and $spot would respond to ^Dog.add_method(bark = method () { ... }); Which would be like doing this in Perl 5: no strict 'refs'; *{'Dog::bark'} = sub { ... }; And of course if you can add a method, you will need to be able to fetch and delete them as well, so a get_method and remove_method would be in order as well. And if you can add methods, surely you can add attributes, so (add|get|remove)_attribute would be needed. ^Dog.add_attribute(:label$fur, :accessrw); Would be equivalent to saying this: class Dog is reopened { has $fur is rw; } And ^Dog would also provide access to infromation about super and subclasses as well. So superclasses and subclasses methods would make sense too. We would also need methods to deal with Role relationships as well. So, given the above items, the class MetaClass might look something like this: class MetaClass { has $name is rw; has $version is rw; has $authority is rw; has @superclasses; has @subclasses; has %methods; has %attributes; method identifier { ... } method superclasses { ... } method subclasses { ... } method add_method { ... } method get_method { ... } method remove_method { ... } method add_attribute { ... } method get_attribute { ... } method remove_attribute { ... } } So given this, you could almost look at this code: class Foo-0.0.1-cpan:JRANDOM { has $bar is rw; method baz (Foo $self:) { ... } } As being roughly equivalent to the following code: ^Foo := MetaClass.new(); ^Foo.name('Foo'); ^Foo.version(0.0.1); ^Foo.authority(:cpanJRANDOM); ^Foo.add_attribute(:label$bar, :accessrw); ^Foo.add_method(baz = method (Foo $self) { ... }); Of course this is mostly unspecced, and it is still unclear exactly how much of this meta-level API will be accessible in Perl 6 itself. And as far the the Pugs work on this goes, we plan to have something similar to the above available in the next release (6.28.0). Hope this helps. Stevan
Re: overloading the variable declaration process
On 2/9/06, Jonathan Lang [EMAIL PROTECTED] wrote: Stevan Little wrote: Jonathan Lang wrote: OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? Well, a metaclass describes the behaviors and attributes of a class, and ^Dog is an *instance* of the metaclass. So actually ^Dog would not actually have attributes and methods since it is an instance. Huh? A dog can bark; so the Dog class should have a method called 'bark'. Or does 'can' not mean what it seems to mean? ^Dog is an instance of the MetaClass, while Dog (no ^ sigil) is the class (actually it's a prototypical instance of the class which the metaclass ^Dog describes, but you dont really need to know that to use it). ^Dog.can(bark) # false Dog.can(bark) # true This is a very important distinction. Saying Dog class has a method called 'bark', implies the following statements are true - Dog will respond to the method called bark. - Given my Dog $spot, $spot will respond to the method called bark. - ^Dog (the metaclass instance which describes a class called Dog) does *not* respond to the method called bark. - ^Dog (since it describes the class called Dog) manages all of the methods which Dog and $spot will respond too, one of which is called bark. There is a clear line between the meta-level (where ^Dog lives) and the user-level (where Dog and $spot) live. This is a line which is heavily blurred in Perl 5, and in many OO languages (aside from Smalltalk, CLOS and a few others) the meta-level is just not accessible at all from user-land. That said, I think ^Dog would probably respond to methods like these (some of which are described in S12): OK; apparently, what I meant when I asked what methods and attributes does ^Dog have? is what you're talking about when you speak of which methods ^Dog will respond to. To me, an object has whatever methods that it responds to. I disagree, an object is an instance of a class. A class has the methods that the object will respond too. You would not want to store all the methods in each instance, it would not make sense. Each instance needs to share a set of methods, and those methods are stored in the class. Well what is a class? In Perl 5 a class is simply a package, and the subs in that package are methods. In Perl 6 however, a class will be an instance of another class, the MetaClass. These two things are really not that different when you think about it. - A Perl 5 package holds methods for you by storing them in the symbol table. You can add, get, remove these methods from the symbol table using the symbol table API. - A Perl 6 class holds methods for you by storing them inside an instance variable in an instance of the MetaClass, and you can add, get, remove these methods by using the methods of MetaClass. Of course you have a conceptual circulatiry issue now because well,.. what is a MetaClass? Well it could be an instance of a MetaMetaClass, but what is that an instance of? This could go on forever (turtles all the way down as it is sometimes called). But in practice you either just stop and say this is as far as it goes, or you bootstrap your class model somehow and tie the knot. I prefer the boostrapping as it is much more elegant and tends to allow for much more flexibility. ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL Would it be valid to speak of ^$spot? If so, what would ^$spot.name be? There is no such thing as a ^$spot. The ^ is the class sigil, and will hold metaclass instances only, just as variables with % will only holds hashes, and variables with @ will only holds arrays, etc. I would like to see some methods like this: # dynamically add a method that # Dog and $spot would respond to ^Dog.add_method(bark = method () { ... }); Which would be like doing this in Perl 5: no strict 'refs'; *{'Dog::bark'} = sub { ... }; IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. or maybe method Dog.bark () { ... } Yes that works too. But TIMTOWTDI, and each has it's own benefits. Your above approach works fine while you are writing the code, but is not as useful for dynamically adding a method at runtime (unless you use eval(), but that gets ugly). Using the metaclass API dynamically adding a method to a class at runtime is trivial, again, think of it as being no different that doing this in Perl 5: # deep within a function
Re: overloading the variable declaration process
On 2/8/06, Jonathan Lang [EMAIL PROTECTED] wrote: Consider my Dog $spot. From the Perl6-to-English Dictionary: Dog: a dog. $spot: the dog that is named Spot. ^Dog: the concept of a dog. Am I understanding things correctly? If so, here's what I'd expect: a dog can bark, or Spot can bark; but the concept of a dog cannot bark: can Dog bark; # answer: yes can $spot bark; # answer: yes can ^Dog bark; # answer: no Yes, that is correct, because: Dog.isa(Dog) # true $spot.isa(Dog) # true ^Dog.isa(Dog) # false In fact ^Dog isa MetaClass (or Class whatever you want to call it). At least that is how I see/understand it. Stevan
Re: A proposition for streamlining Perl 6 development
On 2/7/06, Allison Randal [EMAIL PROTECTED] wrote: On Feb 7, 2006, at 13:28, Yuval Kogman wrote: Apologies if this is insulting to anyone, but personally I think that Perl 6 (pugs, parrot, everything) is losing too much momentum lately. I think we need to seriously rethink some of the implementation plan. I understand your frustration. I even sympathize, as I had to work through this same frustration a few years ago. But, micromanagement is not the answer to lost momentum. I really don't think that Yuval is talking about micromangement. He is talking about refactoring. I think we can all agree that: - Small methods are good - Monolithic God objects are bad Decomposing the problem into smaller and smaller problems until the problems become manageable for a small team of volunteers to work on and understand. It actually makes things worse, as people throw their effort into defining the problem more and more clearly, instead of throwing their effort into producing shippable code. I am not sure if that is Yuval's point either, in fact I think his point is that without defining the problem a little clearer it will be very difficult to actually produce shippable code. If it makes you feel any better, pretty much all projects suffer a loss of momentum after the first year. Well I dont know about Yuval, but that depresses me somewhat :( Parrot, on the other hand, has noticeably gained momentum the past 6 months or so. AFAICT, this is largely due to the fact that we're close enough to finished that we can see the light at the end of the tunnel, and because Pugs reminded us to hold on to our sense of fun. Now I am not as involved in Parrot as I am in Pugs so I might be way off base here, but from my point of view Parrot still has a long way to go before it runs Perl 6 code. Part of that is because the bridge between PIR/PMCs and Perl 6 just does not exist yet (either in code, or even conceptually). Having PGE parse Perl 6 code only gives us an AST, it does not give us running code. And even if we have a nicely massaged AST, running Perl 6 is not a matter of just walking the tree and evaluating it like it is in Perl 5 (of course, I am simplifying quite a bit here). We found (a few months ago) in Pugs that this model just isn't robust enough, and Perl 6 is going to need a more sophisticated runtime environment to support many of it's features. This runtime (or as we have been calling it in Pugs the Object Space) will need to exist on top of Parrot too since it is far to Perl 6 specific to be implemented into the Parrot core. This is the kind of stuff that Yuval is talking about. The missing bits that need to exist in the nether-region between perl6-language and perl6-internals. We are building from the bottom-up (Parrot) and the top-down (Perl 6 - the language) and it seems (at least to many of us on the Pugs project) that there is a big hole somewhere in the middle. Now, I am perfectly willing to admit that I am totally wrong and eat every single one of my words if you can show me the missing conceptual bridge that I am talking about. And please, no hand-waving as that does not produce shippable code. Respectfully, Stevan
Re: A proposition for streamlining Perl 6 development
On 2/7/06, chromatic [EMAIL PROTECTED] wrote: On Tuesday 07 February 2006 14:17, Yuval Kogman wrote: De-facto we have people running PIL on javascript. It works more than parrot does. No, it works *differently* from Parrot, just as an LR parser works differently from an LR parser. Don't make the mistake of thinking Wow, it took Parrot X months to get a working PGE, while the Pugs version only took Y weeks, especially because the Pugs version had the benefit of looking at *already designed, debugged, and tested* Parrot code. The Pugs project and the Parrot project have had very different goals actually (at least Pugs did from the early days). Pugs aimed to be able to evaluate Perl 6 code, as a way of testing the language features and design. It did not really attempt (until the PIL work began) to provide a VM for Perl 6 to run on. And even the PIL work began as a way to strip Perl 6 down to a more managable core calculus which was easier to interpret, the multiple backends seemed to grow out of that as a side-effect. So I guess what i am saying is that I agree with you, comparing Pugs development to Parrot development does not make sense. However, I think we arrive at that conclusion from different angles. It seems to me that Pugs has taken a top-down (more language centric) approach, and Parrot has taken a more bottom-up (runtime/VM centric approach), and in my eyes, there is a big gapping hole in the middle (see my response to Allison's post for details about the big gapping hole). Much of what Yuval is proposing is ways to fill that hole and to decompose and refactor the current Perl 6 development process so that we can have a real production Perl 6 to play with that much sooner. But also have a Perl 6 that some PhD canidate can re-write the type-checker for his thesis project or that some volunteer hobbiest can re-implement the core in FORTH or some open source hacker can hack the circular prelude to make the Schwartzian transformation that much quicker and efficient. IMHO breaking down the project into smaller more digestable chunks carries as much risk of failure as putting all the eggs into single Parrot nest. At the very least, this is a debate worth having, especially since we have all been waiting very patiently for so many years now. Once again... Respectfully, Stevan
Re: overloading the variable declaration process
On 2/7/06, Matt Fowles [EMAIL PROTECTED] wrote: Stevan~ I am going to assume that you intended to reply to perl 6 language, and thus will include your post in its entirety in my response. Yes, sorry... I missed the reply to all button on the gmail UI by a few pixels I guess. Thank you for forwarding. Now that everyone is on the same page, I will go about responding # snip some code class Pipe::Stem { has $composed_of; has $color; has $length; has $filter = bool::false; } so far I am mostly with you, except one question. Does has $filter = bool::false; just provide a default? Yes, that is a default value. I assume that most Pipe smokers don't like filters in their pipes, I might be wrong on that one because I am not a pipe smoker :) You would then model the different pipes you sell; class MagrittePipe { has $stem = Pipe::Stem.new( :composed_ofebony, :colorblack, :lengthshort ); has $bowl = Pipe::Bowl.new( :composed_ofmahogany, :colorbrown, :sizemedium ); } Now, you might say, why not make the MagrittePipe an instance of Pipe, and give the Pipe class a few more attributes, like a name. Well, if you did that then you couldn't subclass it of course. Actually, I was going to ask why not make MagrittePipe inherit from Pipe. Ooops, forgot that part it should infact inherit from Pipe. And of course you can do that dynamically with the metamodel ;) Well, using introspection, it becomes very simple to discover various qualities about your inventory, enough to probably even autogenerate the HTML pages for your online-web store (powered by Perl 6 of course). And lets not forget the uber-cool Perl 6 Object Database which you are using to store your real-time inventory in (all metamodel powered of course). And of course if you want, you can use the DistributedObjectProxy metaclass which will automatically make your objects distributed so that your door-to-door Pipe saleforce can update your inventory in real time from their cellphones. And your RD department can use the built-in (but as yet unspeced) logic programming features of Perl 6 to mine your customer information from your (previously mentioend) object database and genetically grow new, more desireable Pipe products (which is easy to do since your metaclasses are programatically composable (and no I don't mean eval $code)). I think you mis-understand me. I do not question the value of a powerful meta-model. Quite the contrary I want to see Perl 6 have a meta-model more powerful and accessible then CLOS. I see it as a necessity for a language that plans to truely scale in the future. What I do question is the usefullness of having bare class names represent these prototype objects. I just don't really understand what they are for or do. Well, to be totally honest, I think only Larry truely understands their usage, but to the best of my understanding they are intented to serve a number of roles; (Larry, please correct me if I am wrong here) - to allow for introspection of the class. After all ^Foo.can() is really just a series of method calls to the Foo metaobject. And besides ^Foo.meta.can() is 5 more characters to type!! - provide an invocant for class methods. Larry does not like the class-method/instance-method distinction (in fact it seems he doesn't even like the class/instance distinction either), and has declared that a class method is really just a method of the class which does not access any instance attributes. Well, this complicates the type signature of the invocant, and we need an invocant that the type-checker can check. In Perl 5, classes were just package names which were just strings. This will not work in Perl 6 in the presence of a reasonably decent type checker, the class needs to be *something*. Now Larry has also declared that he does not like the idea of a class object, I think this is because that means that a properly typed method signature for a class method would look like this: class Foo { method foo (Class $class:) { say I am a class method, and proud of it; } } According to the signature, this method takes any Class instance as an invocant. Well thats just not right because it should only accept the Class instance which represents the Foo class. But we can't (at least I dont think we can) be that specific, at least not easily enough to also allow this method to be called by an instance of Foo as well. So, the solution, use prototype instances for class objects. So now we can properly type our class method for both Foo and $foo like this: class Foo { method foo (Foo $class:) { say I am a class method, and proud of it; } } And whalla,
Re: A proposition for streamlining Perl 6 development
On 2/7/06, chromatic [EMAIL PROTECTED] wrote: On Tuesday 07 February 2006 15:56, Stevan Little wrote: The Pugs project and the Parrot project have had very different goals actually (at least Pugs did from the early days). Pugs aimed to be able to evaluate Perl 6 code, as a way of testing the language features and design. It did not really attempt (until the PIL work began) to provide a VM for Perl 6 to run on. In my mind, that's the most valuable thing Pugs could do. Well, a few months ago I would have disagreed, but now I agree with you, by taking this down the VM level (which is that the PIL^N/PIL2 runcore is focusing on) is good research for eventually connecting this all to Parrot. I am glad we agree here. And even the PIL work began as a way to strip Perl 6 down to a more managable core calculus which was easier to interpret, the multiple backends seemed to grow out of that as a side-effect. But they're not free to support. Well yes that is very true, but that was a learning process. It helped uncover some of the deficencies in the first PIL implementation (most notable the lack of OO support). It also lead to the development of the Object Space sub-project which is aiming to clarify how we get from Perl 6 to something that is executable in an environment which supports all the features designed. These are both things which the Parrot project and the Perl 6 design project did not address from what I can see. Only after going down some highly experimental paths did this reveal itself. So while I agree, they are not free to support, I would argue that they are RD prototypes and so (to some degree) disposable, and the benefits they have brought in terms of insight into Perl 6 the runtime (not the language, and not the VM, but somewhere in between) are very vaulable. Now I'm not arguing that the existence of multiple backends takes effort away from a single unified backend. This is open development. People work on what they want to work on. Exactly Yuval's point. People want something interesting enough to pique their interest, but small enough to digest for weekend/nighttime hacking sessions. If Perl 6 was broken down in such a way as he proposes, maybe it would attrack more people? or maybe it won't. Neither I or you knowt that, we can only guess. Still, finding the greatest common factor of features between LLVM, Scheme, Spidermonkey, classic Pugs, Parrot, the CLR, the JVM, Perl 5, and whatever other VM is out there means pushing a lot of things up the implementation stack. Sure that's one way to look at it, but it does not need to be that way. Reducing Perl 6 down to a core calculus like PIL actually makes it easier to target any backend you want. And the new PIL^N/PIL2 runcore will make it even easier since all that will be required will be that you create a PIL^N runtime, all the metamodel/container/boxed-type prelude will either be written in PIL^N or in Perl 6. Then the Perl 6 - PIL2 part can be written using PGE/TGE/Parsec/whatever. IMHO this design direction (which makes multiple backends almost trivial) makes for a better more modular and decoupled design in general, which is surely a good thing for all projects involved including Parrot. Much of what Yuval is proposing is ways to fill that hole and to decompose and refactor the current Perl 6 development process so that we can have a real production Perl 6 to play with that much sooner. I agree that that's his goal. I disagree on its appropriateness. What is inappropriate about it? He is questioning the current direction of an open source project which has be regarded as many to be mearly vaporware. Sure you and I know that Perl 6 is chugging right along and making great strides, but until Pugs many people considered Perl 6 to be a joke at best, and total vaporware at worst. I think Yuval has every right to question the direction, and to make suggestions as to how he thinks it can be improved upon. He has put in time on the project, maybe not as much as others, but enough that I think he has a right to speak up if he wants. What is so wrong with that? There are people who can write a bootstrapping compiler from the top down in such a way that normal people can write the user-level primitives in that language. I've met those people. I'm not one of them. There are precious few of them for any language, much less Perl 6. Hmm, quite true, but I think that is mostly because the texts on the subject are so dense and there is a severe lack of hackable projects out there that people can contribute too that don't involve some esoteric language meant to explore some equally esoteric concept. However, that said, the idea of bootstrapping compilers is progressively getting more mainstream. Many of the recent languages which have sprung up for the CLR are moving towards bootstrappability. The new version of Scala is written in Scala. So maybe, as more and more people do it, they will find
Re: A proposition for streamlining Perl 6 development
On 2/7/06, Allison Randal [EMAIL PROTECTED] wrote: On Feb 7, 2006, at 15:31, Stevan Little wrote: Now I am not as involved in Parrot as I am in Pugs so I might be way off base here, but from my point of view Parrot still has a long way to go before it runs Perl 6 code. Part of that is because the bridge between PIR/PMCs and Perl 6 just does not exist yet (either in code, or even conceptually). Having PGE parse Perl 6 code only gives us an AST, it does not give us running code. And even if we have a nicely massaged AST, running Perl 6 is not a matter of just walking the tree and evaluating it like it is in Perl 5 (of course, I am simplifying quite a bit here). We found (a few months ago) in Pugs that this model just isn't robust enough, and Perl 6 is going to need a more sophisticated runtime environment to support many of it's features. This runtime (or as we have been calling it in Pugs the Object Space) will need to exist on top of Parrot too since it is far to Perl 6 specific to be implemented into the Parrot core. This is the kind of stuff that Yuval is talking about. The missing bits that need to exist in the nether-region between perl6-language and perl6-internals. We are building from the bottom-up (Parrot) and the top-down (Perl 6 - the language) and it seems (at least to many of us on the Pugs project) that there is a big hole somewhere in the middle. You imply here that obstacles to implementing Pugs are necessarily obstacles to implementing Perl 6. That's not entirely accurate. Well, the first obstacle I see to implementing Perl 6 can be fixed with the object space work, and I do not see the Perl 6 Object space work as being Pugs specific at all. From work I and others have done on the meta-model as well as the container types, it seems clear that we need a very robust Perl 6 runtime environment. And currently Parrot does not provide enough of that environment. This is not to say that Parrot *cannot*, only that it does not currently. And in my opinion, Parrot shouldn't cater this much to Perl 6 anyway. Parrot's object model is sufficently generic to support the object model of most of the current crop of dynamic languages, but that will not be enough for Perl 6. You just can't compile all the runtime dynamism into PIR and PMCs, you will need a runtime environment (an object space) to support it. The next obstacle to implementing Perl 6 I see is the type-checker/inferencer, this is not the job of Parrot, or of PGE. It a the job for a type inferencer, of which I don't see work on one currently outside of Pugs and Yuval's Blondie work. Then there is the prelude. Why write Perl 6's built-ins in PIR when you can write it in Perl 6? Assuming the Perl 6 codegen is good enough of course. And modern compiler and optimization technology has been doing those things since the late-80s (there are many studies of how compiled Ada code was faster and better than expert hand coded asssembler, there are just some things a computer can do better than a person). I think Pugs and Parrot/PGE share many more obstacles than you might think. But, there is another route, and we're working on it at the same time. From the Parrot perspective, PGE parses the source, its output is translated to an AST (or a couple of intermediate ASTs), and that is translated either to PIR, or directly to bytecode. But this is my point, this won't be enough to support all that Perl 6 is to be. PIR PMCs simply are not enough to have full metaclass support, roles (at compile/class composition time, and runtime), traits, etc. And lets not forget that (to quote Larry in S02 i think) Perl 6 is an OO engine. Which means that container types like Scalars, Arrays and Hashes are objects now too. These things map nicely to some of the current PMCs, but they are not boxed inside the object metamodel, and until they are they are not extendable and usable in the way the language design prescribes. The Pugs project started out with an AST which was then evaluated, which is similar to your AST translated to PIR, and we just found it wasn't enough. Perl 6 is just simply to dynamic a language for that. I'm working on a prototype of this now in Punie, specifically so we can try out the whole path from source code to bytecode. I am familiar with your Punie work as I read your use.perl journal and the Perl 6 meeting notes regularly. But IIRC Punie is a compiler for Perl 1 is it not? Perl 1 is a very very very long way from Perl 6. Perl 6 will get implemented. Oh, of that I have no doubt. Never did, and neither does Yuval (if I may speak for him while he is asleep :). But all that we are trying to do here is shake out some cobwebs, a little spring cleaning if you will. Stevan
Interesting Paper on Prototype Based OO w/ Multi-Methods
Hello All, Recently on #perl6 putter found the Slate language (http://slate.tunes.org/) in our search for some information about Smalltalk. Slate is a prototype based OO language which uses multi method dispatch instead of more traditional method dispatch. As I flipped through some of the papers on the site, I couldn't help thinking back to some of the more recent musing of Larry on the Perl 6 object model. The paper which is most complete is this one: http://tunes.org/~eihrul/ecoop.pdf Or for those with shorter attention spans, there are some slides which give a high level overview of what is in the paper. That can be found here: http://tunes.org/~eihrul/talk.pdf I think there is definitely some valuable information to be found in here, which we can use in the further development of the Perl 6 obejct model. Stevan
Re: as if [Was: Selective reuse of storage in bless.]
On 1/25/06, Jonathan Lang [EMAIL PROTECTED] wrote: Larry Wall wrote: But my hunch is that it's a deep tagmemic/metaphorical problem we're trying to solve here. Such issues arise whenever you start making statements of the form I want to use an A as if it were a B. The problem is much bigger than just how do I translate Perl 5 to Perl 6. It's questions like: What makes a particular metaphor work? Will the cultural context support use of an A as if it were a B? How do we translate the user's thoughts to the computer's thoughts? How do we translate one user's thoughts to another user's thoughts? How do we know when such a translation is good enough? How do we know when our mental model of an object is adequate? How do we know when the computer's mental model of an object is adequate? What does adequate mean in context? Will the culture support partially instantiated objects? :-) That's tagmemics, folks. The main problem with tagmemics is that, while it helps you ask good questions, it doesn't give you easy answers for 'em... Let me take a (feeble) crack at this: It sounds like we're talking about something vaguely akin to C++'s typecasting, where you treat an object of a given class as if it were an object of a different class. Actually this might not be a bad approach in this case. Take this for instance: method foo (Foo $self, $key) { ((Hash) $self){$key} } The syntax is ugly, but it makes what you are doing more explicit. I would also think that in most cases this could be compile time checked (if we can check $self's type (Foo), we can make sure Foo does/isa Hash). Here are some other ideas for a typecasting syntax using as for the keyword (which IIRC is taken for coercion??): $self as Hash { # $self is treated as a Hash inside the block $self{$key} = $value; } # it could also return a wrapped # $self for use in wider scopes my $h = $self as Hash; $h{$key} = $value; Anyway, it's just a early morning (not enough coffee in my system) thought. Stevan
Re: as if [Was: Selective reuse of storage in bless.]
On 1/26/06, Rob Kinyon [EMAIL PROTECTED] wrote: On 1/26/06, Stevan Little [EMAIL PROTECTED] wrote: Actually this might not be a bad approach in this case. Take this for instance: method foo (Foo $self, $key) { ((Hash) $self){$key} } The syntax is ugly, but it makes what you are doing more explicit. I would also think that in most cases this could be compile time checked (if we can check $self's type (Foo), we can make sure Foo does/isa Hash). Here are some other ideas for a typecasting syntax using as for the keyword (which IIRC is taken for coercion??): $self as Hash { # $self is treated as a Hash inside the block $self{$key} = $value; } # it could also return a wrapped # $self for use in wider scopes my $h = $self as Hash; $h{$key} = $value; Isn't typecasting a DesignSmell? This kind of overloading is, imnsho, going to cause more coding bugs and is going to be considered a design flaw in P6. General typecasting is probably a really really bad idea, I agree. But some tightly controlled typecasting (shhh dont call it that or the C/C++/Java programmers will freak out), might be useful in this case. If you like, you can think of this as coercion, and not typecasting, in fact this is probably the better word for it anyway. If there is need to treat something as a Hash, then provide it with a postcircumfix{} and leave it at that. It's highly unlikely that you will want to add Hash-like behavior to something that already has a postcircumfix{} because it probably has that behavior already. Well this is in relation to how to deal with an object which is a blessed p6hash, in which case you may or may not want to have a ^Hash-like interface for it (you might even want to overload the ^Hash-like interface too). So, let me explain myself (hopefully) more clearly. Lets say we treat infix:as as a general purpose coercion operator. So that things like: $num as Str; will pretty much DWIM since a number can be easily coerced into a string (at least 99% of the time, I am sure some of the math whizzes will tell me different so I leave the 1% for that ;). Now, in order for C$self as Hash to make sense, $self would have to be coercable into a Hash in some way. If $self is a blessed p6array this might not make that much sense, so we would die because the coercion failed. However, if $self is a blessed p6hash, then it would make plenty of sense (IMO at least). It would allow us to get at the underlying representation without having to sacrifice flexibility in the class from which $self came. Basically you could do things like this: class Golum; method new (Golum $class, Hash %params) { $class.bless(%params); } method postcircumfix:{} (Golum $self, Any $key, Any $value) { die Nasssty Hobbitses if $value.does(Hobbit); $self as Hash { $self{$key} = $value; } } We could also do this with the p5hash representation too, assuming we have a ^P5Hash of some kind (which is probably not a bad idea really). Anyway, I now have some more caffine in my system (coffee,.. yummy), not that it makes the idea any better, but at least it is more detailed ;) Stevan
Re: as if [Was: Selective reuse of storage in bless.]
On 1/26/06, Rob Kinyon [EMAIL PROTECTED] wrote: On 1/26/06, Stevan Little [EMAIL PROTECTED] wrote: If there is need to treat something as a Hash, then provide it with a postcircumfix{} and leave it at that. It's highly unlikely that you will want to add Hash-like behavior to something that already has a postcircumfix{} because it probably has that behavior already. Well this is in relation to how to deal with an object which is a blessed p6hash, in which case you may or may not want to have a ^Hash-like interface for it (you might even want to overload the ^Hash-like interface too). [snip] Now, in order for C$self as Hash to make sense, $self would have to be coercable into a Hash in some way. If $self is a blessed p6array this might not make that much sense, so we would die because the coercion failed. However, if $self is a blessed p6hash, then it would make plenty of sense (IMO at least). It would allow us to get at the underlying representation without having to sacrifice flexibility in the class from which $self came. Basically you could do things like this: class Golum; method new (Golum $class, Hash %params) { $class.bless(%params); } method postcircumfix:{} (Golum $self, Any $key, Any $value) { die Nasssty Hobbitses if $value.does(Hobbit); $self as Hash { $self{$key} = $value; } } How about just inheriting from Hash? class Gollum extends Hash; method postcircumfix:{} (Golum $self, Any $key, Any $value) { die Nasssty Hobbitses if $value.does(Hobbit); $self.NEXT.{}( $key, $value ); } Well, postcircumfix:{} is not just for emulating Hash :) class struct; has @.struct_def; has $.struct_name; method postcircumfix:{} ($class, Array of Pair @struct, $name) { $class.new( struct_def = @struct, struct_name = $name ); } Then you could do something like this maybe: my $jedi_struct = struct{( first_name = 'Luke', last_name = 'Skywalker' )} = jedi; At least I assume you can, taking advantage of the a class is prototypical instance thing to call postcircumfix:{} like that. But I just might have had too much caffine at this point though ;P Stevan
Perl 6 OO and bless
On Thursday 19 January 2006 21:53, Stevan Little wrote: With p5, you /can/ get to the underlying data structure. This is a break which will hamper the backwards compatibility effort I think. With Perl 5, you can *appear* to get to the underlying data structure. Yet tie() is basically free on Ponie and there's a metaclass mediating access to the underlying storage. I think that makes the problem solvable. Excellent. (Does using an alternate type of storage mean you need an alternate metaclass? Perhaps, perhaps not -- but the practical effects of syntax have to come from somewhere.) Actually I was thinking this might be the best approach. I have been dabbling more and more with CLOS lately and am not seeing where a full-fledge attribute meta-object is probably a really good idea (in the current model the meta-attribute is very very slim). As long as you can use Perl 5 classes in Perl 6 without rewriting all of the Perl 5 code, I'm happy. Yes, this is the ultimate goal. I never wanted to get rid of bless, only to resolve what I saw as an inconsistency with the use of bless and some of the other aspects of the Perl 6 design. Stevan
Re: as if [Was: Selective reuse of storage in bless.]
Larry Wall wrote: On Fri, Jan 20, 2006 at 09:35:13PM +0800, Audrey Tang wrote: My original intent was #2, hence the wording in A12. But to speak to some of Stevan's concernes, there's something going on here which is not quite Object does Hash. It's more like Object can do Hash, in the linguistic sense that a Noun can do Verb, but nonetheless remains a noun. A fallback role is not the same as a normal role. Maybe there's some way to mixin in a fallback Hash role without clobbering a real Hash role that is already there, so that if your Hash container is an object you don't see methods for its keys. Something like this might also let us distinguish p5ish scalars that are simultaneously Num and Str from scalars that, say, intrinsically do Num but can emulate Str in a pinch without caching the result. I don't think we have a good way of expressing that distinction right now. I agree it is a hairy subject, but the more I think about this (and the more i read about and play with CLOS) I think we might be able to accomplish something very close to this by creating more special purpose attribute meta-objects. By moving much of the actual attribute accessing work to the attribute meta-object, we can very easily have arbitrary object types since all their access is mediated through the attribute meta-object. In CLOS this would be accomplished by subclassing the standard-class, and telling it to use the different attribute meta-object by default. The of course you slap a juicy LISP macro around it, and you are ready to go. Mm LISP macros :) Basically my point is that the meta-classes and meta-objects govern the behavior of the classes and object. So if we want to change the behavior of our classes and objects, we just subclass the meta-classes and meta-objects and specialize the behavior as we desire. This seems to imply that a given role like Hash could have two default implementations--one for an actual Hash container, and one that emulates a Hash by deferring to the Object. It's sort of like a role that can delegate back to its own object. This should all be possible with attribute meta-objects. Basically when we encounter this type of need (in p5-p6 translated classes, or otherwise), the compiler (or possibly the translator) needs to discover this need, and change the metaclass appropriately. The self delegation then Just Works. Of course this is all just hand-waving right now since the current metamodel does not support such deep magic. But hey, I have been thinking it might be time for a v3 soon anyway :) Such issues arise whenever you start making statements of the form I want to use an A as if it were a B. The problem is much bigger than just how do I translate Perl 5 to Perl 6. It's questions like: What makes a particular metaphor work? Will the cultural context support use of an A as if it were a B? How do we translate the user's thoughts to the computer's thoughts? How do we translate one user's thoughts to another user's thoughts? How do we know when such a translation is good enough? How do we know when our mental model of an object is adequate? How do we know when the computer's mental model of an object is adequate? What does adequate mean in context? I am actually working with Rob Kinyon on a meta object protocol for Perl 5 for our $work. It does not try to make Perl 5 anything it is not, instead it only attempts to define the workings of the Perl 5 object system and provide clean hooks into it. It is in the very early stages, and needs lots of testing, but it might help to bridge the two models. Will the culture support partially instantiated objects? :-) Hmm, do you mean lazy objects? As in, only instantiated as much as is absolutly necessary at a particular moment? I recently read a paper on an extended version of CLOS (yay CLOS) which demonstrated how lazy classes could be built, including ones with strict initialization orders ($a must be initialized before $b, but $b depends on $c, etc). But maybe this is not what you mean. Or is this the class but undef idea again? Audrey and I have solved this by creating a 'p6undef' repr type which allows the class to be instantiated and methods called on it, but if you try to access anything other than basic meta information, it will fail (because it's just undef). Actually, I think this partial object thing needs it own thread really. But I will let you decide when you are ready for that one :) Stevan
Re: Perl 6 OO and bless
On 1/18/06, chromatic [EMAIL PROTECTED] wrote: On Wednesday 18 January 2006 18:54, Stevan Little wrote: Or are you thinking that a Perl 6 value should be blessed into a Perl 5 package? That's closer to what I had in mind. I think there is a real serious issue here since the hash the Perl 5 package would be expecting is a ref to an HV, and the Perl 6 value it would be getting would be an instance of the ^Hash class (itself a subclass of ^Object). This is actually where i see the fundemental problem with a Perl 6 bless which is capable of blessing Perl 6 references. There are no Perl 6 references like we had in Perl 5, they are *all* objects now. Would not the Perl 5 layer see the Perl 6 instance of ^Hash as an object? If not, then we must already have a Perl 6 opaque (the ^Hash instance) to Perl 5 HV converter/proxy/ magic- jellybean/thunk so I don't need to write it :) Why would Perl 6 bless() bless references? I've always seen it as specifying the underlying storage container for the object's instance data. (Hey, my last rigorous reading of S12 predates my current project. I could be wrong.) If that predates the latest update then you should read again. It hasn't changed all that much on this subject though so maybe not. I think the problem is that S12 is kind of fuzzy about this underlying storage/alternate repr for opaque issue. Without a really clean and well reasoned description of all that, and how it all works together there will be little hope of Perl 6-Perl5 interoperability on the level you desire. If Ponie is there and this code runs on Parrot and Ponie uses Perl 5 PMCs, they're theoretically available to Perl 6, with the proper invocations or magic or thunking or whatever. Well, yes, we can push this all down to Parrot, which IMO is the right place for it to be handled. But in that sense then Perl 6's interaction with Perl 5 will be no different than Perl 6's interaction with (Python | Ruby | Tcl | etc). Which means there will be some restrictions on the depth of the interaction. If we want to have the level of interoperability which you seem to think we should have (and I tend to agree with you that it would be nice), then we need to either; 1) Have a Perl 6 OO - Perl 5 OO thunking layer This would mediate things between the two OO models so that neither would have to be restricted by the other. This would be possible with some minor (but fairly complex) extensions to the Perl 6 MOP. Basically we would need to create a Perl 5 MOP of sorts which would have the appropriate thunks in the appropriate placed to make things Just Work. 2) Force some basic rules/restrictions upon the interoperability. Well to start with, if Perl 5 code would need to treat the Perl 6 code as black boxes. It wouldn't be able to do $self-{attr}, it would have to do $self-attr(). The Perl 6 code would have to handle the Perl 5 data structures in a similar way (not sure the details of that though). There would also need to be some rules about inheritence. Perl 6 uses the C3 algorithm to determine the method resolution order, while Perl 5 uses the depth-first-left-to-right approach. This would mean that a Perl 5 class which uses multiple inheritence with some Perl 5 classes and some Perl 6 classes would have a rather hairy time determining the method resolution order. Maybe we would say that the Perl 6 class would *have* to use pre- order (depth-first-l-to-r) and could not use C3. I could go on here, but there are enough mismatches between the two OO models that there would have to be some kind of ruleset. Or maybe you are you thinking that a Perl 6 class can inherit from a Perl 5 class? Absolutely. See the inheritence/MRO mismatch I described above. This would apply here big time. It is not a trivial issue either. To be honest, i think this is better handled with delegation, and can even be automated using the attribute delegation features described in A/S12. I have serious doubts about round-tripping with delegation, having tried to do it. I want to subclass a Perl 5 class with Perl 6 code and use objects of that class within Perl 5 code without them having to know that I'm doing something sneaky. It'll be a true pity if that's *truly* impossible. Maybe delegation would be nasty, but so would be mixed MROs. You say TOE-mato, I say TOW-mAto. The biggest problem with this would be object initialization. The normal Perl 6 BUILDALL/BUILD code could not be used here since Perl 5 does not have the meta-object protocol to support such behaviors, nor is there a common enough Perl 5 object initialization idiom to work with here. The end result is that you probably end up having to do a bunch of manual initialization code. Sure, but that's a per-representation thunking layer writable in Perl 6 code. It might be somewhat tricky, but it's not completely hideously
Perl 6's bless is (seriously) broken
Hello, I am forking this off the Perl 6 OO and bless thread since that seems to have gotten bogged down in what it all means to Perl 5 interoperability. This was not really my intent with the original thread, but I think it is still a fruitful discussion so I will re- make my original point here with more detail. First I need to establish a few things on which my argument rests. So, S02 says that Perl 6 is an OO engine. Which means that a hash is not a literal thing but an instance of the class ^Hash. This means that a hash now has methods which can be called on it, and inherits from ^Object. Because @Larry does not want the OO-ness of the language to get in the way of doing ones job, all the methods of ^Hash are either transformed into pseudo-built-in-functions using macros (see the Hash/ delete/UnaryForm part of S29), or would be aliased as multi-subs which dispatch using MMD. Take this (very simplified) pseduo-code for exists: method Hash::exists (^Hash %h: Any $label) return Bool { %h{$label} ?? bool::true !! bool::false } And lets assume that a macro has been written to make it callable in the built-in function style which will transform this: exists %h{'foo'} Into this: %h.exists('foo'); Now, what happens when we bless a hash. class Foo { method new ($class: %params) { $class.bless(%params); } method bar ($self:) { ... } } The result of Foo.new is an instance of ^Foo. In Perl 5, the hash would be tagged with the package name it was blessed into, but it would still be a hash reference, only now you could also call methods on it. This *won't* work the same in Perl 6 though. This is because, what is blessed is not a literal hash, but an instance of ^Hash. If we follow the Perl 5 logic, then we can now call methods on this blessed hash, but we cannot use the hash built-in functions since they are just macro transformations into method calls. Take this code example: my $foo = Foo.new({ one = 1, two = 2 }); exists $foo{'one'}; # this will not work The reason this the above code will not work is because exists $foo {'one'} will be transformed by the macro to $foo.exists('one'), which will fail since no Foo::exists exists. Even if we tried to do this (and assuming the macro would DWIM): Hash::exists $foo{'one'}; This would fail anyway since Hash::exists is expecting a ^Hash instance as it's invocant arg, and not a ^Foo instance, so it would fail on the parameter/argument type check. I think this is a deep problem with how bless works, how the container types work, and maybe even how our MMD system works. I think we need to have a well reasoned solution to this which is devoid of any magic hand waving. Thanks, Stevan
Re: Perl 6's bless is (seriously) broken
On Jan 19, 2006, at 4:10 PM, Rob Kinyon wrote: Packages don't have anything to do with the class system. Actually ^Class.isa(^Package) ;) Stevan
Re: Perl 6's bless is (seriously) broken
Juerd, On Jan 19, 2006, at 4:10 PM, Juerd wrote: Stevan Little skribis 2006-01-19 15:45 (-0500): class Foo { method new ($class: %params) { $class.bless(%params); Wouldn't that be %params.bless($class), or more directly, %params.blessed = $class? Nope, according to S12: As in Perl 5, a constructor is any routine that calls bless. Unlike in Perl 5, you call it as a method on the class, passing the candidate as the first argument. It then does on to give this code example: $object = $class.bless({k1 = $v1, k2 = $v2, ...}); In fact all example using bless us it as a method of the $class. This *won't* work the same in Perl 6 though. This is because, what is blessed is not a literal hash, but an instance of ^Hash. The mistake here is that Foo doesn't does Hash, I think. But we cannot automagically inject a role into a class, for a number of reasons. 1) thats just plain evil 2) what if the role conflicts with other roles being does-ed by Foo? Debugging hell there. 3) What if Foo wants to have a .keys, .value, .exists, etc? Do they shadow the Hash version? What if Foo.keys is implemented using Hash.keys? Many issues abound here. Sure, in Perl 5, you could have different kinds of references as instances of the same class. But I don't recall ever having encountered that. bless([] = 'Foo'); bless({} = 'Foo'); bless(\*Foo = 'Foo'); bless(\(my $var) = 'Foo'); It silly, but you could do it. However this is not really related to my point. The issue I am describing looks more like this in perl 5: package Hash; sub new { ... } sub keys { ... } sub values { ... } sub exists { ... } package Foo; sub new { my ($class, $hash) = @_; ($hash-isa(Hash)) || die hash needs to be an instance of Hash; bless($hash, $class); } Why would you ever want to do such a think in Perl 5? So why would that be how bless works in Perl 6? Stevan
Re: Perl 6's bless is (seriously) broken
Juerd, On Jan 19, 2006, at 4:21 PM, Juerd wrote: Juerd skribis 2006-01-19 22:18 (+0100): Could you live with @foo being an array, and @foo in scalar context returning a reference to that array? And with arrays being interfaces to underlying Arrays, which are objects, which makes arrays non-objects that can be used *as* objects? This turns everything is an object into everything can be used with OO syntax, which I think is more true Alternatively and simultaneously, everything represents an object. Well, if everything is NOT an object, then the synopsis need to reflect this. I was under the impression that everything was an object, some of that object-ness is more hidden in some than others, but it does not mean they are not still objects. My point though was not to debate OO theory, but to reconcile a problem in the Synopsis and it's description/usage of bless. Currently it is broken, and we need to fix it. One fix, yes, is to say arrays and hashes are not objects, they are literals as in perl 5. Personally I am not sure that is a good approach, and seems to contradict more of the Synopsis then it agrees with. Stevan
Re: Perl 6's bless is (seriously) broken
On Jan 19, 2006, at 5:09 PM, Juerd wrote: Stevan Little skribis 2006-01-19 17:06 (-0500): This turns everything is an object into everything can be used with OO syntax, which I think is more true Alternatively and simultaneously, everything represents an object. Well, if everything is NOT an object, then the synopsis need to reflect this. I was more thinking along the lines of NOT everything is an object, but some things are. sarcasm Hmm, maybe we can add an Object context then. It would allow an something to be an object only when it is convienent for it to be so. ;) /sarcasm Stevan
Re: Perl 6's bless is (seriously) broken
On Jan 19, 2006, at 5:19 PM, Jonathan Scott Duff wrote: On Thu, Jan 19, 2006 at 11:07:49PM +0100, Juerd wrote: Stevan Little skribis 2006-01-19 16:59 (-0500): 2) what if the role conflicts with other roles being does-ed by Foo? Debugging hell there. Very good point. Aren't role conflicts resolved at composition time (possibly by failure)? That doesn't sound like debugging hell to me, but rather clear indication of a problem and the location of that problem. Role conflicts are resolved when a role (or set of roles) is composed into a class. In this case the (automatically generated) code would look something like this: method new ($class: %params) { my $self = $class.bless(%params); $self does Hash; return $self; } Or it would have to detect it in the class definition itself, in which case it would add a does Hash; to the class def somewhere. The reason this would be debugging hell (IMO at least) is that *I* never told it to does Hash, so as far as I knew there was no clashes in the roles I composed. Sure if was educated in the finer points of Perl 6 I would know what happened, but a random newbie would be half- way to PHP by now. Stevan
Re: Perl 6 OO and bless
On 1/19/06, chromatic [EMAIL PROTECTED] wrote: Next question. If Ponie and Perl 6 are both running on Parrot, and if Ponie has PMCs that represent Perl 5 data containers, such as p5hash, p5array, p5symbol, and so on, what's the problem with having a Perl 6 object that uses one of those PMCs as its internal storage? Okay, so when you say alternate storage then you mean that a class like this: class Foo { has $.bar; method new ($class, %params) { $class.bless('p5Hash', %params); } method baz { $.bar += 1; } } should use a PMC representation of a p5 hash as it's storage, and that the method baz does the right thing here? Because that makes sense to me. However, what doesn't make sense would be if I had to write baz like this: method baz { self-{'bar'} += 1; } In other words, if this is just a detail of the storage, and does not affect user code at all, then I am okay with it. This though would mean that you would not have direct access to the underlying data structure (the p5 hash). I realize one of Stevan's objections is But if you use a Hash, does your object automatically support the .keys method and .kv and so on? to which I reply No, of course not. That's silly. It just uses the Hash for *storage*. Okay, then I assume you mean it to behave the same way as with the p5hash, that it is completely transparent to the user that you are using a p5hash or a p6hash or a p6opaque? In which case,.. I say okay. But note again that you have not provided access to the underlying data structure (the p6hash a.k.a - an instance of ^Hash). Is that your objection to bless()? Yes, that is my objection, because while the alternate storage approach discussed above is actually a very interesting feature, it does not fit with the p5 vision of bless. With p5, you /can/ get to the underlying data structure. This is a break which will hamper the backwards compatibility effort I think. I don't mean to handwave here -- there are definitely issues to consider when crossing a language boundary related to method dispatch (and the last I remember from design meetings was things change there and you shouldn't expect that they stay the same), but the resistance to allowing different storage types for objects completely baffles me. Yes, this will be an interesting one :) Or is the question about Why is there a need for bless() when you can already pass arguments to CREATE()? In that case I dunno. Well as you say in your reply to Rob, TIMTOWTDI. I will agree with you here if they are in fact 2 ways to do the same thing. This would actually solve and simplify some issues in the metamodel currently. And to be honest, I have absolutely no real objection to bless. I just don't think the current treatment of it is consistent with some of the stated goals of the Perl 6 design. Stevan
Perl 6 OO and bless
Hello All, In reading over the Synopsis again in hopes of finding more information regarding the different repr types (see the warnocked post entitled Construction and Initialization of repr types other than P6opaque), I stumbled onto some issues with the Perl 6 OO model and bless. In S02 it says: Perl 6 is an OO engine, but you're not generally required to think in OO when that's inconvenient. However, some built-in concepts such as filehandles will be more object-oriented in a user-visible way than in Perl 5. Now taking this statement one (logical) step further, and I assume that this means things like arrays and hashes will (underneath) just be objects. So we will have an ^Array class, and a ^Hash class, and [] and {} will actually construct instances of ^Array and ^Hash respectively. (Of course I am simplifying it here, these may be roles instead of classes, but this is not relevant to the discussion really). Then later on S12 says: As in Perl 5, a constructor is any routine that calls bless. Unlike in Perl 5, you call it as a method on the class, passing the candidate as the first argument. To bless a hash as in Perl 5, say: $object = $class.bless({k1 = $v1, k2 = $v2, ...}); Are we not just re-blessing an instance of the class ^Hash into whatever $class is? That does not seem to be what is intended, however, if {} is a constructor for an instance of ^Hash, and I can call methods on {} like any other object ({}.keys, {}.exists($key), etc.), then what happens when I bless {} with a class? Do I loose access to the methods of ^Hash? Are the methods only allowed to be called in the non-invocant syntax (called like functions and not methods)? Which brings me to my real question: Do we really still need to retain the old Perl 5 version of bless? What purpose does it serve that p6opaque does not do in a better/ faster/cleaner way? Thanks, Stevan
Re: Perl 6 OO and bless
On 1/18/06, chromatic [EMAIL PROTECTED] wrote: On Wednesday 18 January 2006 14:13, Stevan Little wrote: Do we really still need to retain the old Perl 5 version of bless? What purpose does it serve that p6opaque does not do in a better/ faster/cleaner way? Interoperability with Perl 5 code. How so? Please elaborate how you see this working? Are you thinking that one would be able to bless a Perl 5 reference into a Perl 6 package? I would argue then that we really don't need Perl 6 bless for this, and we can just use Perl 5's bless. After all, if Perl 5 can call Perl 6 functions, then Perl 5 will need to understand Perl 6's packages, and vice-versa. If this is true then Perl 5's bless should be able to accept a Perl 6 package value and DWIM. However, this would probably be a somewhat ugly solution to whatever problem it is you are trying to solve since your Perl 6 code would be weighted down with Perl 5 OO-isms. In fact, I would argue that doing it this way is not the right way, and instead using Perl 6 OO and delegating to a Perl 5 object is a better option. Or are you thinking that a Perl 6 value should be blessed into a Perl 5 package? I think there is a real serious issue here since the hash the Perl 5 package would be expecting is a ref to an HV, and the Perl 6 value it would be getting would be an instance of the ^Hash class (itself a subclass of ^Object). This is actually where i see the fundemental problem with a Perl 6 bless which is capable of blessing Perl 6 references. There are no Perl 6 references like we had in Perl 5, they are *all* objects now. Would not the Perl 5 layer see the Perl 6 instance of ^Hash as an object? If not, then we must already have a Perl 6 opaque (the ^Hash instance) to Perl 5 HV converter/proxy/magic- jellybean/thunk so I don't need to write it :) Or maybe you are you thinking that a Perl 6 class can inherit from a Perl 5 class? To be honest, i think this is better handled with delegation, and can even be automated using the attribute delegation features described in A/S12. The biggest problem with this would be object initialization. The normal Perl 6 BUILDALL/BUILD code could not be used here since Perl 5 does not have the meta-object protocol to support such behaviors, nor is there a common enough Perl 5 object initialization idiom to work with here. The end result is that you probably end up having to do a bunch of manual initialization code. And let's not forget that our Perl 6 blessed hash is not the same as the Perl 5 blessed hash, so there might be confusion/issues there too. We also have the issue here of where does ^Object fit into our inheritance now? Is the Perl 5 package the top of our @ISA tree? or do we insert ^Object in there somewhere too? Or maybe you are you thinking that a Perl 5 class can inherit from a Perl 6 class? Well since Perl 5 inheritance is really just a package name in the @ISA, this is trivial to get method inheritance since Perl 5 already can understand Perl 6's packages. And lets assume that the Perl 5 new uses the (somewhat common) idiom and just calls SUPER::new(@_) and re-blesses the returned Perl 6 instance. Let's assume too that the Perl 6 constructor just blessed a Perl 6 instance of ^Hash. Again we have the mismatch between the ref to an HV and the ref to an instance of ^Hash. This brings us back to our Perl 6 opaque (the ^Hash instance) to Perl 5 HV converter/proxy/magic-jellybean/thunk thingy. So in conclusion, I think that a Perl 6 bless which acts like a Perl 5 bless is not as useful as your seem to indicate. It is certainly not the magic bullet of interoperability. I don't think we can really avoid not having a p6opaque-p5-blessed-ref magic-thunker. However, maybe I am missing something here, if so, please elaborate and explain. Thanks, Stevan
Re: Perl 6 OO and bless
On Jan 18, 2006, at 10:41 PM, Trey Harris wrote: Excuse my ignorance of the finer points, but I thought the reason for bless's continued existence was so that the same sort of brilliant OO experimentation that Damian and others have done with pure Perl 5 can continue to be done in pure Perl 6 without having to hack p6opaque? Actually bless only partially plays a role in all those whacky things which so many whacky people have done with Perl 5. Without AUTOLOAD, symbol table hacking and closures, bless would not be that exciting. However, given a proper MOP (meta-object-protocol) the amount of Object Oriented experimentation which will be possible in Perl 6 will far exceed what you can do in Perl 5. Not to mention that it will also be type-safe and far more reliable (read: you could *actually* use it in production). And not to put down all of the brilliant OO experimentation that has been done in Perl 5, but it is not always as cutting edge as one might think. A good amount of the really crazy cutting edge OO work is being done with either Smalltalk or CLOS and the fact they both have well defined and studied MOPs is probably a major reason for that. Stevan
S12: Possible contradiction in responsibilities of Class Object
Hello all, I have been reading the recently updated Synopsis 12, and a few things jumped out at me. In the Classes section, classes are described like this: Classes are primarily for instance management, not code reuse. Later in the same section the following is stated: Every class is an instance of its metaclass. You can get at the metaclass of any object via the .meta method. Later on in the Construction and Initialization section, the following comment is made: All classes inherit a default Cnew constructor from CObject. Now, making the assumption that instance management includes the creation of new instances, which I think is a reasonable assumption to make. It would seem that new should not be a method in Object, but instead a method of the class (aka - the MetaClass instance). This would then mean that MyClass.new() would be really mean MyClass.meta.new() (which is not without precedence since .isa and .can work the same way). I would then describe Object's role in this as the initialization of new instances, as Object is where it makes the most sense for BUILDALL and BUILD to reside. Stevan
Construction and Initialization of repr types other than P6opaque
Hello again, In Pugs, we are currently trying to figure out how classes are initialized with $repr types other than P6opaque. My interpretation of S12 is that P6opaque types are initialized as follows (by default): new is called with named arguments, it then calls bless passing in 'P6opaque' as the $repr type, and the named arguments after it. bless then calls CREATE, which constructs the opaque type using all the attributes of the class (which are collected in 'descendent' (BUILD) order). At this point BUILDALL is called, which itself calls all the BUILD methods is can find (again in 'descendent' order). S12 lists several other $repr types which CREATE accepts such as P6hash, P5hash, P5array, PyDict Cstruct. Some of these types are more conducive to construction in the manner in which CREATE constructs P6opaques. These seem to be separate from the $canidate argument for bless, which seems to work similar to how P5's bless worked. So my question is: What is the purpose of the different $repr types? Should the other $repr types be used in the same manner as P6opaque? Just alternate types of internal storage. Or should using these other $repr types act more like blessing these same/similar types (blessing a hash, blessing an array, etc). Thanks, Stevan
Re: Role Method Conflicts and Disambiguation
On Nov 2, 2005, at 9:02 PM, Jonathan Lang wrote: Let's say you have this: role A {method foo() { code1; } } role B {method foo() { code2; } } role C does A does B { method foo() { A::foo(); } method bar() { B::foo(); } } Should the following be valid? role D does C { method foo() { B::foo(); } } IMHO, it shouldn't, because D doesn't do B. Not valid in what way? Should this be a fatal error? Are you implying that B is not local to D, so it cannot use it? that somehow disambiguation must be done using one of your local subroles only? I think this is too restrictive, D should be able to freely disambiguate or override using anything it want's to. It need not be related at all to it's subroles. Stevan
Re: Why submethods
Luke, On Oct 29, 2005, at 3:42 PM, Luke Palmer wrote: Another thing that scares me with the utility sub point of view follows: class Foo { method process_data($data) { $.help_process_data($data); } submethod help_process_data($data) { $data+1; } } Foo.new.process_data(0); # 1 class Bar is Foo { } Bar.new.process_data(0); # dies[1] What??? I didn't change anything yet! Why does it die? (This is the first principle in the journal entry you quoted) This is true, but I think that it is easily rectified. A submethod is said to have an implicit next METHOD unless $?SELF.class =:= $?CLASS I think we could add onto that and say that in addition to checking the invocant's class, we could also check the calling context, and do like we do with private methods, and allow things like this to Just Work. However, it could also be that the creator of Foo did not intend for subclasses to be able to Just Work, and that the whole idea of Foo is to do a Template Method style pattern in which subclasses must implement the help_process_data submethod in order for things to work. This is an entirely valid usage for a submethod, and in fact, I think it is an excellent way for implementing the Template Method pattern. It is also possible that we could bring over the role idea of required methods and have the same basic principle relate to classes and submethods. If marked as such, a submethod is required to be implemented by a subclass, or class composition fails. I think that could be a useful feature which would allow very safe re-use along those lines. Anyway, just my 2 cents. Stevan
Re: Role Method Conflicts and Disambiguation
Yuval, On Oct 28, 2005, at 10:59 AM, Yuval Kogman wrote: On Thu, Oct 27, 2005 at 22:19:16 -0400, Stevan Little wrote: Now, at this point we have a method conflict in suspension since (according to A/S-12) method conflicts do not throw an error until a role is composed into a class. This means that when I do this: class MyClass does FooBar {} an exception is thrown. Unless of course MyClass has a foo method, which will disambiguate the conflict. My question then is, can FooBar (the role) disambiguate the foo conflict? IMHO yes, but it doesn't have too. It should be able to leave it to the class to decide. If we allow the class to decide if things break or not, then we potentially allow for the system to be in a very unstable state. A method conflict means that neither method gets consumed, and at that point we have a gapping hole in our class. IMHO we should not allow this to be decided by the user in any other way then to disambiguate,.. otherwise we should die very loudly. In the end, we will have probably looked inside every method defined in Foo, Bar, FooBar and Baz in order to properly write MyClass2. IMHO, this is sort of defeating the usefulness of roles at this point. I disagree - you have to know what a role is actually giving you to exploit it. Too much black boxing makes your programming language seem like a Kafka story. Why? does it introduce bugs? ;-P So what do you all think?? Role method conflicts should only be dealt with if the user knows what the roles are actually doing anyway. This will probably be familiar code, and if not it warrants familiarity. Agreed. I don't think we can let the user use library code without being aware of the library code internals at all. Abstraction that works like this is usually either crippled or useless. 90% of the time you don't want to know, but there are exceptions. A little extreme, but I tend to agree with your point. Stevan
Re: Role Method Conflicts and Disambiguation
On Oct 28, 2005, at 11:17 AM, Jonathan Scott Duff wrote: On Thu, Oct 27, 2005 at 10:19:16PM -0400, Stevan Little wrote: I have a question about method conflict resolution works for roles, and I cannot seem to find this in any of the Apoc/Syn documents. Here is the basic issue: role Foo { method foo { ... } method bar { ... } # we will use this later :) } role Bar { method foo { ... } } role FooBar { does Foo; does Bar; } Now, at this point we have a method conflict in suspension since (according to A/S-12) method conflicts do not throw an error until a role is composed into a class. This means that when I do this: If we say that the roles Foo and Bar are composed into the role FooBar and that method conflicts trigger an exception at composition time (whether composed into a role or class), then your above declaration of FooBar will trigger an exception and force the user to resolve the conflict. Well, if we allow FooBar to die, then we do not allow for possible disambiguation by a class (which is the only place it matters anyway since roles cannot be directly instantiated). I think that not keeping the conflict in suspension until the role is composed will actually restrict the usefulness of roles. I should be allowed to create a role with all sorts of conflicts which I leave for the classes to deal with. Remember that if you create a role with a stub method (method my_stub { ... }) then it acts just like a conflict does in requiring the consuming class to implement it. Stevan
Re: Role Method Conflicts and Disambiguation
On Oct 28, 2005, at 11:38 AM, Jonathan Scott Duff wrote: On Fri, Oct 28, 2005 at 04:59:18PM +0200, Yuval Kogman wrote: If, OTOH we have a diamond inheritence: You mean composition. There is no role inheritance :) role A { method foo { ... } } role B does A {}; role C does A {}; class D does A does B { }; I'm assuming you meant class D does B does C { ... } I'm not sure we need to resolve the conflict. It depends on when composition happens. If A is composed immediately into B and C as soon as the role is processed, then when D is being composed, all it sees are a foo method from the B role and a foo method from the C role. If, however, roles aren't composed into other roles but only into classes, then I think that class D does B does C { ... } would be equivalent to class D does A does B does C { ... } since the roles B and C would carry the uncomposed A role along with them. Personally, I think the later makes the most sense. This fits very well with the roles are just containers idea. A role flattens method, attributes, *and* subroles too. If, on the other hand, we have role X trusts Foo does Foo { has $:foo; } Quoth A12: It's not clear whether roles should be allowed to grant trust. In the absence of evidence to the contrary, I'm inclined to say not. We can always relax that later if, after many large, longitudinal, double- blind studies, it turns out to be both safe and effective. Has that changed? To quote $Larry[0] A12 should be read for entertainment purposes only I know, that scares me too ;) Stevan
Re: Role Method Conflicts and Disambiguation
On Oct 28, 2005, at 2:54 PM, Jonathan Scott Duff wrote: On Fri, Oct 28, 2005 at 02:29:36PM -0400, Stevan Little wrote: I should be allowed to create a role with all sorts of conflicts which I leave for the classes to deal with. Er, why? I've read this sentence several times and I'm really having trouble grasping why anyone would deliberately create a conflicted role and want to postpone the conflict resolution until later. Well, certain classes might want to deal with the conflict in certain ways. role Foo { method foo { [ 1, 2, 3 ] } } role Bar { method foo { { one = 1, two = 2, three = 3 } } } role FooBar { does Foo; does Bar; method display_foo { self.foo.values.join(', '); } } class MyFooArray does FooBar { foo := Foo::foo; } class MyFooHash does FooBar { foo := Bar::foo; } The conflict here basically allows the user of FooBar to determine what kind of data structure to use, while also providing basic means of displaying the data structure. The example a little contrived, but it might be a useful technique in some areas. It seems to me that conflicts should be resolved sooner rather than later. Especially in the light of run-time composition: role A { method foo { ... } ... } role B { method foo { ... } ... } role C does B does A { ... } my Dog $spot; ... $spot does C; Well why should this be any less dangerous that this: my $spot = (class { does A; does B; }).new(); Which is what it will be desugared into anyway. It might also be possible for the compiler to catch this kind of stuff too. Would you rather wait until perl is actually executing that last line of code before finding out there's a conflict or would you rather know there's a conflict at compile-time (when C is immediately composed of A and B)? To be totally honest, I think if you do runtime role composition with a role which you know has a conflict (I mean I assume you either created that role, or know what it provides before you use it), then you deserve all the pain and suffering associated with it. Yes, I realize that Perl6 already has the problem that run-time composition could cause conflicts, but I want to have a slightly smaller chance of running into it :) Actually, according to the for entertainment purposes only A12, if I do this: $spot does Dog does Cat; I am really doing this: $spot = (class { is (class { does Dog; }); does Cat; }).new(); So it won't actually conflict. Stevan
Re: Role Method Conflicts and Disambiguation
On Oct 28, 2005, at 3:04 PM, Jonathan Scott Duff wrote: But, I'm probably wrong about this as the X role may have methods that use $:foo in one way and the Y role may have methods that use $:foo in some other, incompatible way, so perhaps there will be a conflict just as when there are 2 methods of the same name. Yes, they have to conflict. Attribute conflict rules should be the same as method conflict rules. Stevan
Re: Role Method Conflicts and Disambiguation
On Oct 28, 2005, at 3:45 PM, Rob Kinyon wrote: Doing it any other way leads to the following: if A does rA and B isa A and B defines an attribute that conflicts with the one provided by rA, how on earth is that supposed to be detected? Especially given that the inheritance tree of a class can be modified at runtime. B should not know or care that A does rA, because by the time B gets to A, rA has already been consumed by A. If B does not want it's attributes to conflict,.. make 'em private. If rA is concerned that it's attributes will get mussed with, it should make 'em private too (which IMO would mean that A gets a new private attribute, not that it is privatet to the role). Your method (as we have discussed in the past) means that Roles now have instance specific data, which needs to be stored somewhere, somehow (not too difficult). And our class now needs to keep information about the roles it composed around so that it can dispatch to methods appropriately (also not too bad). This then means that the method dispatcher, when it cannot find a private method locally, needs to check all the roles which were composed into the class to find the correct private method and then call that method (I assuming no method conflicts here, but they can (and will) happen). The method then needs to be able to find and extract the role specific private instance data (this action itself requires some complex access control checks), and then do something with it. Like I said, this is assuming we have no conflicts, because the dispatcher will have a hard time determining which role specific private method named :foo you mean in the context this is all happening in. And if we check for conflicts up front, we start to run into the same issues that we did before. One possible solution might be to only allow methods defined within the role to access the private role methods. But then what happens if that method is in conflict. Here is an example: role Foo { has $:bar; # this is role private data method :get_bar { $:bar } # a role private method method gimme_bar { self.:get_bar() } # the public face to the private role data } class Blah does Foo { method gimme_bar { ... } } At this point :get_bar and $:bar are totally inaccessible. IMO, roles should be just containers, and they should hand over everything they have to the class they are composed into. I also think Subclasses should not care what roles their superclasses consumed, that is personal information for the class only to know. Stevan
Re: Role Method Conflicts and Disambiguation (Theory-theoretic take)
Luke, On Oct 28, 2005, at 9:44 PM, Luke Palmer wrote: It was the fact that at each stage of the game, we summarized the defaults and requirements for each role, ignoring the internal makeup (i.e., what roles were composed into it, etc.). This then imposes somewhat of an ordering with role composition. The role tree will need to be traversed breadth first, and conflicts/ requirements resolved on a level by level basis. And it sounds correct to me. It sounds correct to me as well (in theory,.. get it ,... in theory :P). However, I do worry about how it will work out in practice. Part of the goal of roles (and I have been preaching this one since the hackathon) is that they are easier to use than multiple inheritance, have fewer headaches than mix-ins and are more useful than interfaces. Imposing ordering as described above may make things easier, or it may make things harder, only time and experience will tell. I am going to give this some more thought over the weekend, and see what I come up with. Stevan
Role Method Conflicts and Disambiguation
Hello all, I have a question about method conflict resolution works for roles, and I cannot seem to find this in any of the Apoc/Syn documents. Here is the basic issue: role Foo { method foo { ... } method bar { ... } # we will use this later :) } role Bar { method foo { ... } } role FooBar { does Foo; does Bar; } Now, at this point we have a method conflict in suspension since (according to A/S-12) method conflicts do not throw an error until a role is composed into a class. This means that when I do this: class MyClass does FooBar {} an exception is thrown. Unless of course MyClass has a foo method, which will disambiguate the conflict. My question then is, can FooBar (the role) disambiguate the foo conflict? role FooBar { does Foo; does Bar; method foo { ... } } Now, on the surface this seems obvious, of course the FooBar role should be able to disambiguate. However, when we expand the example other issues show up. role Baz { does Foo; } class MyClass2 does FooBar does Baz {} # Will this die? Now, since MyClass2 actually does Foo twice, does that mean bar creates a conflcit? Since bar would be found through FooBar and Baz. I would think the answer here would be no, and that we would build some kind of unique list of roles so as to avoid repeated consumption like this. But thats not all, we have a potential problem with foo again. Baz will provide foo from Foo, but FooBar will provide it's own foo (which we used to disambiguate). So our disambiguation is not ambiguated again. / Possible Solutions / A (deceptively) simple solution to this is that MyClass2 needs to disambiguate. But this means that our roles are not really black boxes anymore. In order to properly disambiguate this we need to know where all the foo methods are coming from (Foo, Bar and FooBar), and potentially what is inside these foo methods (especially in the case of FooBar since it is attempting to disambiguate, it's behavior could be very specific). It probably would also become important to know what other methods foo interacts with since we potentially have 3 different expected versions of foo. In the end, we will have probably looked inside every method defined in Foo, Bar, FooBar and Baz in order to properly write MyClass2. IMHO, this is sort of defeating the usefulness of roles at this point. Another simple (but maybe slightly unintuitive) solution would be to not allow roles to disambiguate at all. (Quick side note: Doing this means that roles like FooBar (which carry with them a suspended conflict) would be restricted in what types of behaviors they can provide. Basically they would only be able to provide new behaviors which are unrelated to those provided by Foo and Bar. If it were to try to use methods from Foo or Bar, it would really end up needing to disambiguate.) This actually makes MyClass2 somewhat simpler now, since it only need to disambiguate between foo from Foo, and foo from Bar. Of course this is only marginally better, since you would still need to look inside all the methods of Foo, Bar, FooBar and Baz to see how foo is being used so you could disambiguate properly. ... So what do you all think?? Stevan
Re: Ways to add behavior
On Oct 26, 2005, at 12:05 PM, Larry Wall wrote: Of course, there are other words that are somewhat synonymous with class, Unfortunately sort is already hosed. Maybe kind. Actually kind is used in the Core Calculus for Metaclasses paper which I brought to the hackathon (not sure if you got to read it or not). Here is a link: http://research.sun.com/projects/plrg/core-calculus.pdf They present an rather interesting view on things, that the definition of the instance creating portion of a class should be seperated from the class or kind portion of the class. Actually the first metamodel prototype grew out of an implementation of the model they describe in the paper. Stevan
Re: txt vs OO [was: Re: Proposal to make class method non-inheritable]
On Oct 25, 2005, at 6:31 AM, Michele Dondi wrote: On Fri, 14 Oct 2005, Stevan Little wrote: I think Perl 6's OO system has the potential to be to OO programming what Perl 5, etc was to text processing. This, I believe, is in large part due to Sorry for replying so late. Thought it seems appropriate to post this in this time of Perl 6 fears and rants threads... Well, the point is that it is interesting to note that text processing is an _application area_, whereas OO programming is a programming language paradigm. Allow me to clarify. Perl 5 (and below) are known by outsiders (non-perl users) as being a really good language for processing text. Ask any friend you know who has had little or no exposure to Perl and they will probably tell you this. Of course they will also tell you that it is all line noise, etc, etc etc. This is the most common perception of Perl by those people who have (for the most part) never encountered it. I think that Perl 6 may become like that for OO. When people who have never used or encountered Perl 6 talk about it, they will say, I've never used it, but I hear it has lots of really cool OO features. Just as now they the same thing re: text-processing. Sure, this means nothing to people who are actually using it, but this is mostly about outside perception. These kinds of things are sometimes what will bring people to the language initially, so they are not to be taken lightly. Despite the intro above, this is not meant to be a rant or to express a fear. But it is intended to raise a meditation. After all, being known for text processing capabilities may be somewhat restictive and not faithful of Perl's (including Perl 5) full potentiality, Of course not, Perl is also used for CGI, but you can do that better with Java now (which is a real language cause it's compiled) ;) People who are not familiar with a language tend to rely heavily on the common knowledge about that language. And also tend to hold tightly to the myths and pseudo-facts surrounding their own languages. The combination of these two things tends to lead to silly statements like the one above. but OO programming is somewhat immaterial either, the only relevance being the suitability for big projects management. The idea that OO is only relevant for big projects is just as silly as saying that Perl is only good for text processing. Sure I would not use OO to write a small utility script, but the modules I access in the script would probably be written using OO. And those may be very small modules too, but their re-usability is greatly enhanced by various OO features (encapsulation, ability to compose-into or use within another class, etc etc etc). This kind of thing (IMHO) is why so many people are being drawn to Python and Ruby. Hopefully Perl 6 can draw them back. Stevan
Re: Ways to add behavior
Larry, On Oct 25, 2005, at 4:37 PM, Larry Wall wrote: On Mon, Oct 24, 2005 at 06:33:20AM -0700, Ashley Winters wrote: : # behavior through prototype -- guessing realistic syntax : Base.meta.add_method( : do_it = method ($arg) { : say doing $arg!; : }); : : : # or, just add it to a single instance : $x.meta.add_method( : do_it = method ($arg) { : say doing $arg!; : }); I don't have a comment on your actual question, but I'd like to use this opportunity to point out the symmetry of Base and $x at this point, and the fact that .meta can't simply call .add_method in the metaclass, or it would lose track of the original invocant, which is needed to convey both class and instance information. I'm not sure it's even possible to say $m = $x.meta; $m.addmethod($arg); The only way that can work is if $x.meta returns a shadow class that is prebound only to $x. (Though that might explain how .addmethod knows it's only adding a method to the object.) This is actually the principe behind the Ruby style singleton methods (the shadow class), it basically creates an anon-class which inherits from $x's original class, then it rebinds/blesses $x into the anon- class. It is very simple really :) As for if this is/should be accessible through .meta, i am not sure that is a good idea. The reason being is that .meta brings with it the idea of metaclasses, which then relates to classes, and so now the user is thinking they are accessing the metaclass of the class of which $x is an instance. I would suggest instead that we have a method, which is found in Object which allows instances to add methods to themselves (and only themselves). In Ruby this is called 'add_singleton_method' or something like that. I use that same name in the metamodel prototype too. In the absence of that, what's going on seems more like $x.META::addmethod($arg); where META:: is smart enough to dispatch to the proper metaclass without throwing away the invocant, and then the metaclass decides what to do based on the instancehood of $x. I am not sure I like this for 2 reasons. 1) META:: smells like ::SUPER, and that feels like re-dispatching to me, which is not really what we need to be doing. 2) there is not need to send this back to the metaclass level. The whole thing could be accomplished as an instance method of Object. Here is how it could be done. class ShadowClass does Class {} class Object is reopened { method add_singleton_method (Str $label, Method $method) { if ($?SELF.class.class != ShadowClass) { my $shadow = ShadowClass.new(); $shadow.meta.superclasses([ $shadow ]); $?SELF.class = $shadow; } $?SELF.class.meta.add_method($label, $method); } } Stevan
Re: syntax for accessing multiple versions of a module
Larry, On Oct 19, 2005, at 4:10 AM, Larry Wall wrote: On Tue, Oct 18, 2005 at 07:38:19PM -0400, Stevan Little wrote: : Then this is added as Dog-0.0.2-cpan:LWALL into the main symbol : table. Then once the compilation process is complete, I traverse the : symbol table hierarchy collecting all the names. Any duplicate short : names (Dog) are noted for later. Once I have collected all the names, : I build all my aliases. : : So if I find: : : use Cat-0.0.1-cpan:JRANDOM; : : only once, I build an alias for (at a minimum) Cat and Cat-0.0.1. But you have to have the aliases there for correct parsing. Otherwise Cat is a bareword, which is illegal. Of course, you can add the alias without deciding what to bind it to. In fact, within a method, we require Cat to be considered a virtual name, so if a derived class uses a different Cat, it means that one instead for this object. I suppose this could be done earlier in the compilation process then, possibly we can make assumptions along the way and alias short names immediately, only to retract the alias later if we see something that conflicts. Assuming we do not encounter any user-level aliasing, I think this would probably be okay. However, this brings up an issue I was thinking about. Take this code for instance: use Cat-0.0.1; use PetStore; my Cat $kitty .= new(); --- in PetStore.pm --- use Dog; use Cat-0.0.5; Which Cat is used? I can see several options: 1) Cat-0.0.1 is used since it is in the local scope, so clearly the users choice. 2) Cat-0.0.5 is used since it is loaded after Cat-0.0.1. 3) An Ambiguity error is thrown because Cat is not specific enough. Any option other than 1 requires the user to know what is going on within PetStore. : For my duplicates, the table would look something like this I think: : : Dog = Dog-1.2.1-cpan:JRANDOM : Dog-1.2.1 = Dog-1.2.1-cpan:JRANDOM : Dog-0.0.2 = Dog-0.0.2-cpan:LWALL : : We are explictly giving the preference to the later version number (I : think we discussed this at the Toronto hackathon). Hmm, don't remember that. But I have a bad memory. To be honest, I am not sure who I discussed it with, it might have been autrijus. Either way it was in the early days of the hackathon, and being a not-so-exciting topic, it was quickly forgotten about for much cooler topics :) To be honest, I don't really like this approach anyway. : Another school of thought would be that Dog alone would be : considered ambiguious and so we would just alias far enough to be : clear, like this: : : Dog = Ambiguity Error! : Dog-1.2.1 = Dog-1.2.1-cpan:JRANDOM : Dog-0.0.2 = Dog-0.0.2-cpan:LWALL : : Of course, this means that if I also load Dog-1.2.1-cpan:LWALL that : the table looks like this: : : Dog = Ambiguity Error! : Dog-1.2.1 = Ambiguity Error! : Dog-0.0.2 = Dog-0.0.2-cpan:LWALL : : And the user is now forced to add the cpan id to get Dog-1.2.1. I am : not sure how strict @Larry wants this to be. I think $Larry wants to be strict on this, at least this week. Horray! If you're using two different versions explicitly within the same scope, you should probably be required to alias one of them. The main purpose of version co-existence is for different modules to use different versions, not the same module. I think using two different versions from the same module is going to be relatively rare. Well, the first thing that comes to mind is that you could create a best-of-both-worlds proxy object/module. Say some insane CPAN developer radically changes an API, some of the changes make senses, some of the changes clearly illustrate the developers insanity. It might be useful to be able to create some kind of mix-up of the two module versions in which you alias part of each API (assuming they can co-exist peacefully that is). Sure it's an out-on-the-edge case, but I could see some possible usefulness. Stevan
Re: subclassing associated classes elegantly
Darren, Your problem reminds me of the Expression Problem, which is something that IIRC Luke's Theory idea was trying to solve. Here is the link to a paper Luke referred me to on the subject: http://scala.epfl.ch/docu/files/IC_TECH_REPORT_200433.pdf Also, you can Google the phrase Expression Problem and find quite a bit on the subject. Stevan On Oct 19, 2005, at 6:11 PM, Darren Duncan wrote: I'm in a long-standing situation with my module development where I want to design a set of associated classes such that invocations of submethods or class methods, such as new(), of one class by another class continue to work as expected when any or all of those classes is subclassed. I have a solution already that works, but I'm looking for the most optimal solution. An example of when this situation can arise is if person X implements a simplified XML DOM implementation using 2 classes, Document and Node, that work together, where one of those classes (Document) can create objects of the other (Node), and person Y wants to subclass the XML DOM implementation, meaning that those same Node objects made by one of person Y's Document subclass should be objects of person Y's Node subclass. To illustrate, say we had these 4 classes (the syntax may be wrong): # This is one associated class set: class A { submethod one () { return 'hello'; } submethod two () { B.four(); } } class B { submethod three () { A.one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: class C is A { submethod one () { return 'world'; } } class D is B { submethod four () { return 'there'; } } What I want to be able to do is set things up so that user code can do something that is effectively like this: my $first = A.two(); # returns 'here' my $second = B.three(); # returns 'hello' my $first = C.two(); # returns 'there' my $second = D.three(); # returns 'world' The situation is that classes C and D represent any arbitrary named 2 classes that are subclassed from A and B, and so the latter can't know the names of the former, and the latter have to work independently of C and D also. This is one variant of a solution I have come up with: # This is one associated class set: role AB { submethod name_of_class_A () { return 'A'; } submethod name_of_class_B () { return 'B'; } } class A does AB { submethod one () { return 'hello'; } submethod two () { .name_of_class_B().four(); } } class B does AB { submethod three () { .name_of_class_A().one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod name_of_class_A () { return 'C'; } submethod name_of_class_B () { return 'D'; } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } This is another variant of a solution I have come up with: # This is one associated class set: role AB { submethod invoke_one () { return A.one(); } submethod invoke_four () { return B.four(); } } class A does AB { submethod one () { return 'hello'; } submethod two () { .invoke_four(); } } class B does AB { submethod three () { .invoke_one(); } submethod four () { return 'here'; } } # This is separate and optional associated class set: role CD { submethod invoke_one () { return C.one(); } submethod invoke_four () { return D.four(); } } class C is A does CD { submethod one () { return 'world'; } } class D is B does CD { submethod four () { return 'there'; } } In either case, the expectation here is that the submethods of role CD will override those of role BC regardless of which class' other methods invoke those, when the invocant class is C or D. So I'm wondering what is the best way to develop my associated class sets such that it is easiest for third parties to be able to subclass-extend them. Should I use one of the two solutions above (both of which have been tried in real life, in Perl 5, the second more recently)? Or is there another solution that is better than both? Also, in such a situation as the above, is it reasonable to support easy subclassing, or would it be better to avoid that complexity and instead expect users to create objects that wrap the others instead of subclassing them? Assume also that it may be counter-productive for one class to expect user code to invoke the second class on its behalf, such as if when pair of classes is hidden behind a second pair of classes that
Re: top 5 list needed
Uri, Well, aside from what is actually *in* Perl 6 currently, there are a number of interesting side projects, which may or may not get included in the final language design. Such as: On Oct 18, 2005, at 3:40 AM, Uri Guttman wrote: the new OO design (stole the best from the rest and perlized it) The current object model prototype (not yet totally approved) is a self-bootstrapping meta-circular object model which is heavily influenced by the CLOS Meta Object Protocol and Smalltalk. It includes several features which are not found in any of your traditional OO languages, such as Roles (which are a descendent of Traits, I could site some papers here is this would help). You might also want to include Luke Palmer's current work on Attribute Grammars and the Theory model. Both of these are very Haskell-ish. I will let Luke speak about those. Yuval Kogman's recent Exceptuation proposal (the marriage of exceptions and continuations, this exceptions you can *actuallY* recover from) is very similar to the condition system of Common LISP. There has also been much work on a type inferencing system for Perl 6 (type *checking* if just old-skool, all the cool kids infer). The fact Pugs is written in Haskell (a language only a professor could love) might be a help. There is also the new Perl 6 packaging system. It will be far more complex than the Perl 5 one, since it will not only include the 3 part name (Foo-0.0.1-cpan:JRANDOM), but it will probably need to support seperate compilation units as well. This is borrowed from everywhere, but specifically we have looked at Fortress (the new scientific progamming language from Sun) and the new .NET assembly model. Thats about all I can think of now. Stevan
Re: top 5 list needed
On Oct 18, 2005, at 1:45 PM, Luke Palmer wrote: On 10/18/05, Rob Kinyon [EMAIL PROTECTED] wrote: 3) Macros. Nuff said. Not quite. Lispish macros, that is, macros that let you look at what you're expanding. To further expand on this, they will be AST-manipulating macros (LISP style) rather than text-replacing macros (C style). Stevan
Re: syntax for accessing multiple versions of a module
Nicholas, This is addressed in S11, here is a link: http://search.cpan.org/~ingy/Perl6-Bible/lib/Perl6/Bible/S11.pod To summarize, the syntax to load the modules is: use Dog-1.2.1; While the syntax to create a specific version of a module is: my Dog-1.3.4-cpan:JRANDOM $spot .= new(woof); I addresses the class creation syntax partially in the initial version of the Metamodel prototype, which was built in p5. I basically just aliased the package with the long name (%{Dog-1.3.4- cpan:JRANDOM::} = %{Dog::}). However this does no good for loading of modules. I have been giving this some though though, and here is a rough sketch of what I have come up with so far. Any module loaded is stored into *:: (or the p5 *main::) as the longest name given. This means that if I do this: use Dog-1.2.1-cpan:JRANDOM; Then I have an entry for Dog-1.2.1-cpan:JRANDOM in the symbol table. If, further along in the compilation process, I encounter another Dog, such as: use Dog-0.0.2-cpan:LWALL; Then this is added as Dog-0.0.2-cpan:LWALL into the main symbol table. Then once the compilation process is complete, I traverse the symbol table hierarchy collecting all the names. Any duplicate short names (Dog) are noted for later. Once I have collected all the names, I build all my aliases. So if I find: use Cat-0.0.1-cpan:JRANDOM; only once, I build an alias for (at a minimum) Cat and Cat-0.0.1. For my duplicates, the table would look something like this I think: Dog = Dog-1.2.1-cpan:JRANDOM Dog-1.2.1 = Dog-1.2.1-cpan:JRANDOM Dog-0.0.2 = Dog-0.0.2-cpan:LWALL We are explictly giving the preference to the later version number (I think we discussed this at the Toronto hackathon). Another school of thought would be that Dog alone would be considered ambiguious and so we would just alias far enough to be clear, like this: Dog = Ambiguity Error! Dog-1.2.1 = Dog-1.2.1-cpan:JRANDOM Dog-0.0.2 = Dog-0.0.2-cpan:LWALL Of course, this means that if I also load Dog-1.2.1-cpan:LWALL that the table looks like this: Dog = Ambiguity Error! Dog-1.2.1 = Ambiguity Error! Dog-0.0.2 = Dog-0.0.2-cpan:LWALL And the user is now forced to add the cpan id to get Dog-1.2.1. I am not sure how strict @Larry wants this to be. I have been meaning to do some kind of p5 prototype of this, I can push it up the TODO list if it would help you. Stevan On Oct 18, 2005, at 5:41 PM, Nicholas Clark wrote: Sorry if I'm asking a question that I've missed in a synopsis. Perl 6 will be able to load more than one version of the same module. As I understand it, this would let you have more than one version of DBI loaded in the same interpreter, and also have DBI written by Tim Bunce and DBI written by A.U.Thor in the same interpreter. Is the syntax for accessing different versions of the same module from Perl nailed down yet? Specifically this is in reference to wondering if the multiple module trick would actually be possible in perl 5: http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2005-10/ msg00585.html and how to do something functionally like: my $foo = DBI(1.38)-new(); my $bar = DBI(1.40)-new(); or whatever to distinguish which you wanted to call a class method on. Nicholas Clark
Re: Re(vised): Proposal to make class method non-inheritable
Miroslav On Oct 17, 2005, at 7:35 AM, Miroslav Silovic wrote: [EMAIL PROTECTED] wrote: I think what bothers me most about this is that it seems there is no way to tell the difference between class methods and instance methods. That the distinction is only made when the body of the method does something which is is not supposed to do (method called with a class invocant attempts to access an instance variable, etc). This is one of the major problems that I have always had with Perl 5 OO. That there is a very fuzzy fuzzy line between the responsibilities of a class and an instance. I can see the notion of a class which is not yet instantiated, this makes sense in many contexts. But I don't think that in order to have this, we need to bring back this element of Perl 5 OO. I think we can still have all the behaviors you have been describing, and still keep classes and their instances as distinct entities. It just recently occured to me that Class is a Package. Actually, to be precise, Class is a Module, and Module is a Package. Modules add the version and authority portions to the name of a Package, and it seems that exporting (as traits?) are Module things, and not Package things. So, on the object model level, class methods/attributes belong to the Package part of a class, while instance methods/attributes belong to the Class part of a class - insofar as they're made distinct by use of my/our. Well, currently in the prototype, class attributes defined with our are stored in the Classes symbol table (which is inherited from Package). Discussions with autrijus lead me to not address class attributes defined by my, since he felt they would be better addressed as normal variables within the scope of the class body. This is somewhat of an implementation detail, however, I think it may also play a part in how these things work. For instance, in the following example, is $.foo a class attribute? or just a local variable for the inner block? class Bar { our $.bar; { my $.foo; } } I assume that the leading $. is what makes the difference, however, IIRC the $. is just part of the name, and no more special than that. Which means that I can choose that name (yes, it is evil, but I assume I can still do it). But given that the variable will be accessible to all methods via the closure mechanism, the only thing missing I think is the ability to get at the variable via introspection. Now, as for class methods, I suppose it is possible to just stash then in the classes symbol table like with variables. However, do we then loose the method call syntax? This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. I am also not sure what you mean about multi-methods either, could you please explain more? Thanks, Stevan
Re: Re(vised): Proposal to make class method non-inheritable
Larry, On Oct 14, 2005, at 2:15 PM, Larry Wall wrote: Look guys, I want it to just consistently be method bark (Dog $d) {...} regardless of how instantiated the dog is. Think of partially instantiated subroutines via .assuming. A sub is a sub regardless of how much it's been curried. So who cares if it's a complete Dog or a partial Dog, or a completely generic Dog? Nobody cares until you try to call a specific method that relies on some specific attribute. If you call a sub with an incomplete definition, you should be prepared to handle the exception. If you call a method with an incomplete object, you should be prepared to handle the exception. Of course, by that argument, $d should be considered defined even if it's a completely uninstantiated class object. With subs the final proof of actual well-definedness (not to be confused with .defined()) is whether it can be bound to a particular set of arguments. It's a rather lazy definition of well-definedness. I'm proposing that all objects follow the same model of not caring how well they're defined until you actually try to use them for something. I don't think I care any more about whether classes test as defined or not. It's like reality--there are a lot of complex problems where the simplest way to simulate them is via reality itself, and all other simulations are guaranteed to be slower. I think what bothers me most about this is that it seems there is no way to tell the difference between class methods and instance methods. That the distinction is only made when the body of the method does something which is is not supposed to do (method called with a class invocant attempts to access an instance variable, etc). This is one of the major problems that I have always had with Perl 5 OO. That there is a very fuzzy fuzzy line between the responsibilities of a class and an instance. I can see the notion of a class which is not yet instantiated, this makes sense in many contexts. But I don't think that in order to have this, we need to bring back this element of Perl 5 OO. I think we can still have all the behaviors you have been describing, and still keep classes and their instances as distinct entities. But we have to think a bit more about the notion of currying class objects into real objects, or something approaching real objects. This is an interesting thought, I will have to ponder it some, but it has a nice smell. Of course I love indian food and functional programming, so that may be personal bias :) Stevan
Re: Re(vised): Proposal to make class method non-inheritable
Larry, On Oct 15, 2005, at 11:25 AM, Larry Wall wrote: : But we have to think a bit more about the notion of currying class : objects into real objects, or something approaching real objects. : : This is an interesting thought, I will have to ponder it some, but it : has a nice smell. Of course I love indian food and functional : programming, so that may be personal bias :) Could turn out that $obj.assuming is just a generalization of func.assuming. That'd be kinda cool. What would be in the other side of $obj.assuming? Assuming $obj is an instance already, what are we creating with it? Or perhaps you mean Object.assuming()? In which case it would produce some partially instantiated class. Please clarify :) Stevan
Re: Re(vised): Proposal to make class method non-inheritable
Larry, On Oct 15, 2005, at 11:25 AM, Larry Wall wrote: On Sat, Oct 15, 2005 at 10:34:34AM -0400, Stevan Little wrote: : I think what bothers me most about this is that it seems there is no : way to tell the difference between class methods and instance : methods. That the distinction is only made when the body of the : method does something which is is not supposed to do (method called : with a class invocant attempts to access an instance variable, etc). : : This is one of the major problems that I have always had with Perl 5 : OO. That there is a very fuzzy fuzzy line between the : responsibilities of a class and an instance. But you haven't actually said why this is a problem. If you want to know at compile time that a method must be called with an object that has been instantiated, it seems to me that it's pretty easy to tell 99% of the time whether the method body has made reference to $?SELF in some form or other. And if the compiler can determine that, why should the user have to specify it? I think it is a problem because they are two distinct areas of responsibility. A class creates and manages instances, while an object is the thing which the class creates. The object only manages it's own data. As for whether the compiler can tell the difference, I am not sure you are correct here. Take this for instance: class Foo { method bar { $?CLASS.baz(); } } What is bar? A class method? or a instance method? Clearly $?CLASS is valid inside instance methods, and surely you can call methods on $?CLASS within instance methods. There is an ambiguity here. One possible solution of course is that this method is both, that it could basically be this (to use the old A12 syntax): class Foo { method bar (Class|Foo $f:) { $?CLASS.baz(); } } I am fine with that personally. My biggest concern is that we are able to fit the syntax into *a* meta-model. As I said before, I don't have a problem scrapping the current version and starting on v3.0, I enjoy writing and thinking about these things, so you will get no resistance from me. However, I want to be sure that I know what it needs to do, then I can determine if I even need to re-write it or not. : I can see the notion of a class which is not yet instantiated, this : makes sense in many contexts. But I don't think that in order to have : this, we need to bring back this element of Perl 5 OO. I think we can : still have all the behaviors you have been describing, and still keep : classes and their instances as distinct entities. Well sure, they're at least opposite ends of a continuum. But we may usefully smudge the distinction in the middle unless you can show actual damage from this. I don't think there is actually damage, we just have methods which can be called in either context. How to implement this is fairly easy, so I am not worried about that. I am just not comfortable with *all* methods being in this grey area. And as you pointed out in your other message, your notion of class is mostly hidden behind .meta in my scheme of things anyway. And generally the compiler will know by inspection whether the body is referring to the dynamic class through .meta, the static class through $?CLASS, or the dynamic instance through $?SELF. Yes, except in the case I show above, but then we can just use the solution I show above. (And yes, it bothers me that $?CLASS is static while $?SELF is dynamic. The latter is an abuse of the $? sigil, which ought to be reserved for entities known to the compiler. Maybe we should rename $?SELF to something that looks more dynamic. $*SELF is dynamic, but implies global. Hmm, if $.foo() is really a self call, maybe we could make a case for self being $$. Of course, there's never been any controversy here about what to call self, oh no... :-) I don't even want to get into this debate, I am just the meta-monkey, nothing more :) Thanks, Stevan
Re: Proposal to make class method non-inheritable
Piers, On Oct 14, 2005, at 12:14 PM, Piers Cawley wrote: Stevan Little [EMAIL PROTECTED] writes: On Oct 12, 2005, at 5:22 AM, Piers Cawley wrote: We definitely have two instances of A since, B.isa(::A). We also have a fragile implementation of count. :) Sorry, I purposefully made it a kludge as that is usually the way the example is shown in most tutorials about class methods. So, let me see if I have this straight here. You're arguing that, because people are often foolish, we should make it harder to be clever? No, more that people have been lead down the wrong paths all too often based on limitations of language implementation. And that Perl 6 should be moving to correct this problem. Sure that might be un- Perlish in the sense that we are not leaving every way to do it open. But at some point I think you need to shake off the old accumulated crud and start fresh, even if that new way might go contrary to what some people have been conditioned to think. I also do not believe that I am making it harder, as much as I am making it different. Change is hard, but it *is* inevitable. I think Perl 6's OO system has the potential to be to OO programming what Perl 5, etc was to text processing. This, I believe, is in large part due to the fact that Perl 5 had such a slim object system, and Larry intended (based on what I have read in A12) to start fresh from the ground up. That, coupled with Perl's tendency to borrow the best from everywhere, and you have the potential for a really great OO system. And you're using a deliberately broken example as grist to your mill? The example is the canonical example for class methods/attributes, and yes it is broken. However, it's broken-ness only serves to illustrate, what I think is, the misunderstanding of the usefulness of class methods in general. One only needs to take a quick sampling of some of the more popular CPAN modules which sport an OO interface to see that all to often class methods are (ab)used to get what amounts to procedural modules with inheritence. Doesn't sound all that Perlish to me. Perl is many different things to different people, this is part of it's beauty as a language. Perl also has the unique ability to be able to re-invent itself on a regular basis (shell-scripts, CGI, bioinformatics, what next??). I personally think that the definition of what is Perlish and what is not Perlish is not only highly subjective, but ever changing. So I guess what I am saying here is thank you, as I will take that as a compliment ;) Stevan
Lazy Generics side-bar (was Re: Should roles and classes be merged?)
Larry, On Oct 14, 2005, at 1:28 PM, Larry Wall wrote: Generics are somewhat orthogonal to the mutable/immutable distinction, except that they're a better fit for roles because someone has to choose when to instantiate them, and they're easier to understand with early binding rather than late binding. So another way to view the role/class distinction is that roles have eager semantics while classes have lazy semantics. I expect it's possible to do lazy generics, but I would put it in the category of hard things that should be possible. I am not 100% sure what you mean by lazy generics vs. eager generics. But in the current metamodel prototype I have implemented, what I believe to be, lazy generics. It works like so. Say we have a generic Unit class, which needs a type (::T) for it's value: class Unit[::T] { has ::T $.value; } Now I am assuming that a class body is a closure (which surely it is) and that it usually just gets evaluated right away. What if we defer that evaluation? Lets de-sugar the above example a little: my $Unit = sub (::T) { class Unit[::T] { has ::T $.value; } }; Now we have not yet actually created any Unit classes yet (generic or otherwise). Instead we have a closure which given the right set of parameters, can create specific instances of the Unit class which are parameterized. Now we create our Unit[Int] class like this: my $unit_int = Unit[Int].new(); Which would be just sugar for this: my $unit_int = $Unit.(Int).new(); Again, I am not sure if this is what you mean by lazy generics or not. Stevan
Re: Re(vised): Proposal to make class method non-inheritable
Larry, I have been giving a lot of thought to the way you have been describing classes lately. I think I understand where you are going with it, but I need to understand some of the details. On Oct 14, 2005, at 2:15 PM, Larry Wall wrote: This only reinforces my view that all the meta stuff for Dog must be via the .meta or the associated package. There is no Class object. It's a false dichotomy. Class is a role that manages partially instantiated objects, just as Routine (or whatever it is these days) is a role that manages partially instantiated sub calls. And they mostly manage by delegation to .meta. If I understand you correctly then, what I have been calling a class object is just really the thing on the other end of .meta. When I say class object, I mean some kind of object instance which contains all the information to describe a class (methods, meta- attributes, superclass list, etc). This can just as easily be called a metaclass instance too, it makes no difference to me. As for the idea that Class is a role that manages partially instantiated objects, I am not sure i am understanding what you mean here. I am assuming this is along the lines of the Class's are a special form of undef idea. In that case I can see where maybe the Class thing is simply a parameterized role of some kind which has the following behaviors: 1) it evaluates to undef in an expression my Dog $fido; if ($fido) { # this won't run, $fido is not yet defined } 2) it acts as a proxy if a method is called on it my Dog $fido; $fido .= new(); If this is true, then maybe Class looks something like this: role Class[MetaClassType $T] { # evaluate to false in bool context method prefix:? () { bool::false } # probably need to overload some other # operators here too, but I will leave # that for now # the AUTOMETH checks for an calls # any method you attempt to call on # this particular class # ( I am not sure about the details # of the code here, but you get the # idea I think ) method AUTOMETH { $T.can($_).([EMAIL PROTECTED]) } } Then if this were so, then the following: my Dog $fido; Would be de-sugared into: my $fido = Class[Dog].new(); At least this is how I am seeing it currently in my head. Please let me know if I am way off the mark here, I am trying to understand how this all will work. Ideally it can fit into the current meta-model prototype as designed, if not, I have no problem re-writing it again, but I just need to wrap my head around how this should work. Thanks much, Stevan
Re: What the heck is a submethod (good for)
On Oct 13, 2005, at 9:47 AM, Matt Fowles wrote: On 10/13/05, Brent 'Dax' Royal-Gordon [EMAIL PROTECTED] wrote: Luke Palmer [EMAIL PROTECTED] wrote: Okay, I seriously have to see an example of a submethod in use. Likewise. As far as I've seen, submethods are a kludge wedged in for cases where you're actually calling all the way up the inheritence tree. Personally, I've always thought a cascade method syntax would be better for that: post method BUILD($foo, $bar) { ... } pre method DESTROY() { ... } Cascade methods would be called (before|after) the indicated method in a superclass was called. I don't think there is a need to restrict it to the wrapping superclasses methods only, there is no reason that you could not also have them wrap a local method too if you wanted. This might actually be a legitimate use for a submethod too. pre method foo () { ... } # this is inherited submethod foo () { ... } # this is not inherited post method foo () { ... } # this is inherited I could see this construct being quite useful in a Template Method pattern sort of way. Their return values would probably be thrown away. I think they might actually be a sort of syntactic sugar for inserting `call` in the method body, but that's an implementation detail, really... I have always wondered about the absence of these. CLOS has them and they look quite useful. CLOS has before, after and around method qualifiers actually. AFAIK, the return values of these methods are thrown away too, as Brent suggests. One thing to keep in mind is that CLOS has generic functions instead of the usual methods-attached-to-a-class scheme. It also has no (simple) means of calling superclass methods and capturing the return values (at least AFAIK, I am sure someone has hacked the abilities, but I don't think it is part of the spec). The method qualifiers were added to CLOS to allow for this kind of behavior. Since Perl 6 does not suffer from this same issue, method qualifiers are not *needed* like they are in CLOS. That said, they are a nice bit of syntactic sugar (as Brent points out). Maybe this could be done with traits? method BUILD ($foo, $bar) is post { ... } method DESTROY () is pre { ... } Or possibly with some kind of name-mangling: method BUILD:post ($foo, $bar) { ... } method DESTROY:pre () { ... } Stevan
Re: Proposal to make class method non-inheritable
On Oct 13, 2005, at 4:45 PM, TSa wrote: No, not that class has no state, but that with the currently specced classes we have inherited behaviors (class methods) but they do not inherit the accompanying state (class attributes) as well. I see this as potentially very problematic. What do you mean with not inheriting class state? I would think that beeing an instance of a class, an object should have access to the shared class data, but it is not part of the per object state. Or do you mean that class data is not accessable to the instances at all? I would hope that this is 'hidden' in the scopes where the class's parts are defined but of course accessable lexically from class support code there. I mean that classes do not inherit class state along subclass lines. Take this code for instance: class Foo { has $.bar; } every instance of Foo I create has it's own copy of $.bar. Now I subclass it: class Bar is Foo {} every instance of Bar has it's own copy of $.bar as well. Now look at this from the class attribute perspective. class Foo { our $.baz; # class data here,.. not instance data } Foo has a single copy of $.baz in it's internal namespace. Now subclass it: class Bar is Foo {} Bar does not have it own copy of $.baz, in fact Bar's ability to access Foo::{$.baz} (or however it would be spelt) is not more special than any other class in the system. The point I am trying to make is that class data is unique to the class itself, and subclasses of said class do not have any special priviledges or access to that data (leaving auto-generated accessors out of the picture for now). This is different though from how class methods behave, which seems to me to be problematic. Stevan
Re(vised): Proposal to make class method non-inheritable
Well, I suspected there would not be much support for my initial proposal on class methods, but I felt I had to try. Not being the type of person who gives up easily, I want to revise the proposal (incorporating some of the ideas in the responses). I propose that class methods are inheritable, but have the following behaviors/attributes: 1) Autogenerated Class attribute accessors will be submethods. This means that this code: class Foo { our $.bar; } will be functionally identical to this code: class Foo { our $.bar; submethod bar (Class $c:) { $.bar } } This will ensure that class methods which are specifically tied to some kind of state within the class will not be inherited. At least not by default, if you want that behavior, then you can do this: class Foo { our $.bar; method bar (Class $c:) { $.bar } } 2) Class methods be defined more specifically I think that method (Class $c:) { ... } is kind of ugly, and if we use eigenclasses to implement class methods, is not even correct. Ideally we have some kind of way to represent Larry's Dog but undef concept. This could be thought of as being the prototypical instance (for those who like prototype based OO), and it would also be the invocant for all class methods for Dog. So anyway, here are a few ideas, in no particular order: method bark (::Dog $d:) { ... } # not sure if this notation is already taken or not method bark ($Dog $d:) { ... } # not sure I like this one myself, but to me it helps to re- enforce the singleton nature of the class instance method bark (Dog) { ... } # this would be similar to functional languages where the parameter matches a value, not the type of a value. # The user would then be forced to use $?CLASS inside (this one is probably too much BD) classmethod bark { ... } # you can't get more specific than this :) Okay, thats all for now, however, be on the lookout for some other mails on the specifics of class method dispatch. If we are going to do it, we need to do it right. Thanks, Stevan
Custom Metaclass and Inheritance of Class Methods
Hey All, So, given the abundance of positive responses ;) for my class methods don't inherit proposal, I have decided to withdraw that proposal (see my last response on the thread). Of course, this means we now have to work out the details of exactly *how* they get inherited in all situations. The trickiest one being in the presence of custom metaclasses. So, onto the questions. (NOTE: if you get bored about half-way through this mail (and you probably will), there is a conculsion/wrap-up at the very bottom that you can probably safely skip ahead too) Should custom metaclasses are inherited along normal subclass lines? This would mean that if Foo uses CustomMeta as it's metaclass, any subclass of Foo will do the same. This is something Larry mentioned, and something I had been thinking about a lot myself and discussed recently with Rob Kinyon. I drew a diagram in my response to Larry that looked like this: Class ^ : CustomMeta ^ : eFoo...eBar ^ ^ | | Foo...Bar This shows the structure which would be created. The result is that method dispatch would go like this: Bar.foo eBar.get_method(foo) eFoo.get_method(foo) CustomMeta.get_method(foo) Class.get_method(foo) ! No Method Found Error ! I think this makes sense in many ways since CustomMeta can theoretically add capabilities to the Foo class, which one would want inherited by subclasses of Foo. (NOTE: if CustomMeta adds instance methods to Foo, they will get inherited, mostly I am talking about class functionality here) However, I can also see where it would make sense for this *not* to behave this way. But if we the opposite approach, the eigenclass/ metaclass hierarchy begins to get more complex. To start with, we would need to create another anon-class (called xFoo here) which uses multiple inheritence to inherit from eFoo and CustomMeta, then eBar would inherit from eFoo (and through eFoo, to Class), this would keep CustomMeta out of Bar's method dispatch path. Class ^^... : : CustomMeta : ^ : : : xFoo...eFoo...eBar ^ ^ | | FooBar The resulting method dispatch paths would be: Bar.foo eBar.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! Note the lack of CustomMeta in the dispatch path, where as in the above example it was there. This on it's own is not too bad, however, when we add another metaclass, it starts to get busier. Our anon-class xBar must inherit from eBar and CustomMeta2 (just like xFoo did). Then eBar must be connected to eFoo in order to inherit from it, but not pic up any of CustomMeta's methods. Class... ^^... : : : : CustomMeta :CustomMeta2 ^ : ^ : : : xFoo...eFoo xBareBar ^ ^ ^: | :.|: | | Foo..Bar The method dispatch path for this is pretty much the same as above, with the addition of CustomMeta2. This example now actually brings up another issue. What should the superclass ordering be within the x* classes? If eBar comes first, followed by CustomMeta2, then we get the following method dispatch path: Bar.foo xBar.has_method(foo) # xBar should never have any of it's own method eBar.has_method(foo) eFoo.has_method(foo) CustomMeta2.has_method(foo) # this would fall here under C3 Class.has_method(foo) ! Method Not Found Error ! But if CustomMeta2 comes first, followed by eBar, then we get the following method dispatch path: Bar.foo xBar.has_method(foo) CustomMeta2.has_method(foo) eBar.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! The question really is, which has precedence, the custom metaclass, or the local class methods (including class methods inherited along normal class lines)? Now, all these method dispatch paths are using the C3 MRO. And personally I find neither of these approaches to be the best. One alternate (but kind of whacky) approach would be to not use C3 here, but instead use breath-first traversal. Now, this may seem really odd at first, but given the highly regular structure of these class groupings, it might make the most sense. Here is what that method dispatch path might look like: Bar.foo xBar.has_method(foo) eBar.has_method(foo) CustomMeta2.has_method(foo) eFoo.has_method(foo) Class.has_method(foo) ! Method Not Found Error ! Notice how the eBar (which hold's Bar's class methods) is first, followed by the CustomMeta2 class, the followed by eFoo, then onto Class. This specialized dispatching behavior could (I
Re: Proposal to make class method non-inheritable
Gordon, On Oct 11, 2005, at 9:10 PM, Gordon Henriksen wrote: On Tue, Oct 11, 2005 at 06:10:41PM -0400, Stevan Little wrote: I would like to propose that class methods do not get inherited along normal class lines. You mean, make them *not methods?* Because it's not a method unless it has an invocant, as far as I'm concerned. (Method implies polymorphism.) No, they would still have an invocant. That invocant would be an anon- class which itself is an instance of Class. It works like so: (First, lets make a legend) -- is instance of .. is subclass of NOTE: Class means the class named Class, this distinction is important. When you create the class Foo, this is what you have: Class ^ | Foo Foo is an instance of class Class (Class itself is an instance of class Class too, but thats only slightly relevant here). When you add a class method (one which cannot be inherited), it is done with an eigenclass. This changes the above structure into this: Class ^ : eFoo ^ | Foo Now, we have created an anon-class (or eigenclass), whose entire purpose is to hold the class methods of Foo. Since the eigenclass is a subclass of Class, then all of Class's methods are inherited. This means that our method dispatcher does not need to know about class methods as a special case, as far as it is concerned, they are just normal instance methods on Foo (which itself is an instance of eFoo, which is then a subclass of Class). Now, why are they not inherited. Lets expand this diagram a little more: Class ^ +-|+ | | Foo...Bar So Foo and Bar are both instances of Class, and Bar is a subclass of Foo. It is fairly straightforward, but now lets introduce the eigenclasses to hold class methods. Class ^ ..:. : : eFooeBar ^ ^ | | Foo...Bar Now, method dispatch for Foo will go to eFoo (since Foo is an instance of eFoo, and method dispatch always starts at the class-of the instance), and it will continue up to Class (since Class is the superclass of eFoo). The same goes for Bar, first to eBar, then to Class. Since eFoo and eBar are not connected, then normal method dispatching does not go along those lines. Now, this is not to say that it cannot be made to do so. A slight change to the above diagram allows for inheritence of class methods very easily. Class ^ : eFoo...eBar ^ ^ | | Foo...Bar Now, method dispatch for Bar will go first to it's class (eBar), then to any superclasses (eFoo), and any of their superclasses (Class), and so on, and so forth. A better diagram of this can be found here (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ Method_Dispatch_w_EigenClasses.jpg). : Let's start by making a very basic definition of an *object*, : ignoring any implementation details or specifics. : : object == state + behavior I don't see how this is a bad thing. Classes don't have state. That's their lot in life. Que sera! Inheritance of behavior alone is useful. Classes do have state though. They have class attributes: class Foo { our $.bar; my $.baz; } that state is just not inherited. I am not actually arguing that inheritance of just behavior is not useful, more that inheritance of behavior *without the accompanying state* is not useful, and in many cases wrong. My primary want for class methods, as a whole, is to provide this sort of interface in Objective-C: @interface Host : NSObject { - (Class)plugInClass; - (void)setPlugInClass:(Class) plugInClass; } @interface PlugIn : NSObject { - (BOOL)initWithHost:(Host *)host; + (BOOL)supportsFeatureA; + (BOOL)supportsFeatureB; } ... later ... if ([[host plugInClass] supportsFeatureA]) { ... expose UI element ... } My Objective-C is very rusty, but let met see if I understand what you are doing. Host has-a Class object, which it uses as a plugInClass. Your PlugIn then has class methods (supportsFeatureA, supportsFeatureB) which can be used by the Host to query the capabilities of its plugInClass. This type of thing could be accomplished with Roles. class Host { my $.plugInClass; } role PlugIn { method initWithHost (Host $h:) { ... } } role SupportsFeatureA { # yes, this Role has a class method in it, which # the consuming class will get as a class method method supportsFeatureA (Class $c:) { bool::true } } role SupportsFeatureB { method supportsFeatureB (Class $c:) { bool::true } } class AB { does PlugIn; does SupportsFeatureA; does SupportsFeatureB; } One could argue that it is more typing, however, I think that in the long run, it will be less typing since you never need to repeat the supportsFeatureA or supportsFeatureB method, just consume
Re: Proposal to make class method non-inheritable
Piers, On Oct 12, 2005, at 5:22 AM, Piers Cawley wrote: We definitely have two instances of A since, B.isa(::A). We also have a fragile implementation of count. :) Sorry, I purposefully made it a kludge as that is usually the way the example is shown in most tutorials about class methods. class A { our %.count_of method count (Class $c:) { %.count_of{$c} } method BUILD { $class = ($?SELF.class) @countable_ancestors = $class.ancestors.uniq.grep :{.isa(::A)} You can use the MRO here, which is an already linearized list of the inheritance tree (in C3 order) with all duplicates removed. for $class, [EMAIL PROTECTED] - $c { %.count_of{$c}++ } } Where we're assuming I've got the syntax of 'for' right, and that 'ancestors' is a class method that returns all of a class's ancestors. This might not work too well in the face of a dynamic inheritance tree, but it should be possible to work around. Something like this might work: Class A { our %.instance_count_of method count (Class $c: ?$with_descendents = undef) { my @interesting_classes = $c; if $with_descendents { push @interesting_classes, *($c.all_subclasses); } [+] %.instance_count_of(@interesting_classes) } method BUILD { %.instance_count_of($?SELF.class) } } Where we're assuming that a class can find all its subclasses -- Piers Cawley [EMAIL PROTECTED] http://www.bofh.org.uk/
Re: Proposal to make class method non-inheritable
Gordon, It just occurred to me that the system shown below could be re- written to do away with class methods entirely. class Host { my $.plugInClass; } role PlugIn { method initWithHost (Host $h:) { ... } } role FeatureA {} role FeatureB {} role FeatureC {} class AB { does PlugIn; does FeatureA; does FeatureB; } class ABC { does AB; does FeatureC; } Now later on, instead of asking the PlugIn if it supportsFeatureB, you can just see if it does the FeatureB role, like this: if ($host.plugInClass.does('FeatureB')) { # ... do something with FeatureB } This will work with the ABC plugin as well since AB is being treated as a role, ABC will actually consume all it's subroles, which means that ABC will DWIM too. In fact, we get even more from this system since we can check if one plug-in is capable of doing another, because this just works if ($host.plugInClass.does('AB')) { # ... } And since an example is better when it is backed up by working code, I coded this up using the current meta-model prototype. You can see it here: http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/t/ 38_PlugIn_example.t Stevan On Oct 12, 2005, at 9:41 AM, Stevan Little wrote: class Host { my $.plugInClass; } role PlugIn { method initWithHost (Host $h:) { ... } } role SupportsFeatureA { # yes, this Role has a class method in it, which # the consuming class will get as a class method method supportsFeatureA (Class $c:) { bool::true } } role SupportsFeatureB { method supportsFeatureB (Class $c:) { bool::true } } class AB { does PlugIn; does SupportsFeatureA; does SupportsFeatureB; } role SupportsFeatureC { method supportsFeatureC (Class $c:) { bool::true } } class ABC { does AB; does SupportsFeatureC; }
Re: Proposal to make class method non-inheritable
Larry, On Oct 11, 2005, at 8:47 PM, Larry Wall wrote: On Tue, Oct 11, 2005 at 06:10:41PM -0400, Stevan Little wrote: : Hello all. : : I would like to propose that class methods do not get inherited along : normal class lines. I think most class methods should be written as submethods instead. In which case they would not be inherited then. I (obviously) agree with you on that :) You seem to be arguing that a class has no state, but my view is that, in the abstract, a class encompasses the state of *all* its objects. It just hasn't picked one particular object to be at the moment. No, not that class has no state, but that with the currently specced classes we have inherited behaviors (class methods) but they do not inherit the accompanying state (class attributes) as well. I see this as potentially very problematic. : == Instance Counting Class : : The most common example given for class methods is an instance : counter. Here is how one might (naively) look in Perl 6: : : class A { : our $.count; : method count (Class $c:) { $.count; } : submethod BUILD { : $.count++; : } : } That's obviously broken--the count accessor should be a submethod to be consistent, unless the explicit intent is that any subclass of A return the count of A's. Which, not surprisingly, is exactly what you get below. It should probably have been declared: our $.A_count; in that case. And in which case you don't need the explicit accessor, since one would have been provided because of the dot. If you don't want the autoaccessor, don't use the dot. Yes, this example was purposefully broken, but also copied from several tutorial on how to use class methods. I suppose an argument could be made that autoaccessors for class vars should be submethods by default. Or maybe my $.count makes a submethod, while our $.A_count makes a method. I think that is probably not a bad idea. If we not going to inherit the class state, then we should not inherit the class method either. : Clearly, we only have one instance of A, and one instance of B, so : those numbers are wrong. It could be argued that since B is a subtype : of A, we do have two A's, but the argument does not work in reverse. Sure it does. It doesn't matter whether B is a subtype of A or not, you've given it an interface to code that counts A's. True, that was probably a bad example (culled from other bad examples). : But either way, I would argue that the results shown above are : misleading, and probably not what the programmer intended. That's certainly possible, but it wouldn't be the first time people have been surprised that the computer did exactly what they asked it to... :-) Also very true. : Sure, you could do that, however, it complicates the meta-model : unnecessarily. It is much easier to accomplish this using a subclass : of Class. : : class CountingClass is Class { : has $.counter; : method count (CountingClass $c:) { $.counter; } : method new (CountingClass $c: %params) { : $.counter++; : next; : } : } : : class A meta CountingClass {} : class B meta CountingClass {} : : Now A and B both have their own counters neither of which interfere : with one another. Only by forcing people to repeat themselves as a matter of policy. And policy could just as easily have added our $.count to B. The real trick would be to set up A such that you don't have to do anything special in B. I suppose we could say that, by default, if A isa B, then A gets also gets whatever metaclass B has, not the standard metaclass supplied by class. I considered this as well, it seems to make some sense that the metaclass of A is also the metaclass of B if A isa B. This would actually simplify a particular edge case with the eigenclasses that was problematic. This diagram assumes we have inheritable class methods, and they are implemented using the eigenclasses. Class ^ : eFoo...eBar ^ ^ | | Foo...Bar The method dispatch for Bar will go first to it's class (eBar), then to any superclasses (eFoo), and any of their superclasses (Class), and so on, and so forth. When you introduce a custom metaclass like so: Class ^ : CustomMeta ^ : eFoo...eBar ^ ^ | | Foo...Bar A problem occurs with method dispatch for Bar. First it will go to eBar, then to eFoo, then to CustomMeta, then to Class, etc, etc. Since Bar was not explicitly created with CustomMeta, this is not correct. However, if the metaclasses act as you describe, this is then does exactly what it is supposed to. I think it is a sane approach personally. But these are metaclasses, not classes. You keep writing the type of the invocant of class methods as Class, but I don't believe that anymore. Sorry, just following the A12 examples :) The type of the invocant of a class
Re: Proposal to make class method non-inheritable
Gordon, On Oct 12, 2005, at 10:48 AM, Gordon Henriksen wrote: Actually, I wondered why you didn't suggest this earlier. :) I figured you were a step ahead of me: What if I want more than a boolean out of my class method? Then you put the class methods back in :) But then your Objective-C interface would need to change too. Although, the more complexity you introduce, the closer you get to the point when a Factory pattern is just as viable an approach as class methods. Stevan On Oct 12, 2005, at 10:27, Stevan Little wrote: Gordon, It just occurred to me that the system shown below could be re- written to do away with class methods entirely. class Host { my $.plugInClass; } role PlugIn { method initWithHost (Host $h:) { ... } } role FeatureA {} role FeatureB {} role FeatureC {} class AB { does PlugIn; does FeatureA; does FeatureB; } class ABC { does AB; does FeatureC; } Now later on, instead of asking the PlugIn if it supportsFeatureB, you can just see if it does the FeatureB role, like this: if ($host.plugInClass.does('FeatureB')) { # ... do something with FeatureB } This will work with the ABC plugin as well since AB is being treated as a role, ABC will actually consume all it's subroles, which means that ABC will DWIM too. In fact, we get even more from this system since we can check if one plug-in is capable of doing another, because this just works if ($host.plugInClass.does('AB')) { # ... } And since an example is better when it is backed up by working code, I coded this up using the current meta-model prototype. You can see it here: http://svn.openfoundry.org/pugs/perl5/Perl6- MetaModel/t/38_PlugIn_example.t Stevan On Oct 12, 2005, at 9:41 AM, Stevan Little wrote: class Host { my $.plugInClass; } role PlugIn { method initWithHost (Host $h:) { ... } } role SupportsFeatureA { # yes, this Role has a class method in it, which # the consuming class will get as a class method method supportsFeatureA (Class $c:) { bool::true } } role SupportsFeatureB { method supportsFeatureB (Class $c:) { bool::true } } class AB { does PlugIn; does SupportsFeatureA; does SupportsFeatureB; } role SupportsFeatureC { method supportsFeatureC (Class $c:) { bool::true } } class ABC { does AB; does SupportsFeatureC; } — Gordon Henriksen [EMAIL PROTECTED]
Re: Proposal to make class method non-inheritable
Gordon, On Oct 12, 2005, at 11:04 AM, Gordon Henriksen wrote: On Oct 12, 2005, at 09:41, Stevan Little wrote: If you use the BUILD submethod, then you never need to worry about a that, everything is initialized for you by BUILDALL. Now, if you want to have a constructor which accepts positional arguments rather than named pairs (as the default does), then you have a valid need to override new. Whether you should force this upon all your subclasses is a matter of opinion I think. For varying definitions of initialized. I never much cared for the bare poke stuff straight into my instance variables constructor along the lines of: sub new { my($class, %ARGS); return bless \%ARGS, $class; } Yes, that is a horrible idiom which I hope will die in Perl 6. That more or less robs the constructor of the behavior part of class = state + behavior. I need an opportunity to establish my invariants. Well that is where BUILD comes in, you can do all sorts of mangling of parameters in BUILD so that it does what you want it to, there is no real need to put this behavior into new. Of course, when there is no such behavior, it saves a lot of repetitive typing in the class. C# 3 is finally growing a syntax that resolves this by having the language do the repetitive typing at the call site... X x = new X{ Y = 1, Z = 2 }; means X x = new X(); x.Y = 1; x.Z = 2; And X doesn't need anything but the default constructor. Yes, this is exactly what the new - CREATE - BUILDALL - BUILD chain is doing too. Now, this is not to say that it cannot be made to do so. A slight change to the above diagram allows for inheritence of class methods very easily. Class ^ : eFoo...eBar ^ ^ | | Foo...Bar Now, method dispatch for Bar will go first to it's class (eBar), then to any superclasses (eFoo), and any of their superclasses (Class), and so on, and so forth. A better diagram of this can be found here (http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/ docs/Method_Dispatch_w_EigenClasses.jpg). This is more or less how class methods have to work. I would go a bit further, though. Too implement this: Foo : Object Foo : Bar The runtime should use an inheritance tree as such: Object Class : Object Foo : Object Bar : Foo _Object : Class _Class : _Object _Foo : _Class _Bar : _Foo Note that every declared class, including Object and Class themselves, have an anonymous Class subclass that precisely parallels the declared inheritance chain. (Chicken and egg problem? Probably. Object and Class are Special.) This is pretty much the same thing that I am describing, except that I don't think that Class needs an anon-class/eigenclass. All object models need a cycle at the top, this keeps the turtles-all-the-way- down problem away. The usual place is to put the cycle in Class (Class is an instance of Class). If you add that anon-class, you break the cycle. With this implementation, there are three places to put state: In MyObject (instance variable), in _MyObject (class instance variable), or outside of any instance (class variable). The class instance variable is the least useful of the three. Well, I would argue that class instance variables are very useful, since that is where methods and attribute meta-objects are stored. But I think users should not have direct access to class instance variables. But yes, other than that you are correct. Note: I don't see much value in invoking class methods through instances, since a Foo IS_NOT_A Class. If one wants to save the user typing .class when invoking class methods through an instance, Yes, that is bad, another nasty p5 idiom I hope will go away. I would tend toward resolving it as such: class Foo { class_method int Bar(int i) { return i * i; } } -- BECOMES -- # Common interface for Foo's class methods. interface _IFoo { method int Bar(int i); } # The anonymous Class. class _Foo extends Class implements _IFoo { int Bar(int i) { return i * i; } } # The visible class. class Foo implements _IFoo { # Forwards the call to the Class. void Bar(...) { return this.Class.Bar(...); } } I think we can leave the interface part out, but yes, this is basically how the eigenclasses work :) I'll leave the probably obvious role-based interpretation of this to those versed in such. :) s/interface/role/ and you have the role based version ;) Stevan
Re: Proposal to make class method non-inheritable
Brent, On Oct 11, 2005, at 8:17 PM, Brent 'Dax' Royal-Gordon wrote: Stevan Little [EMAIL PROTECTED] wrote: I would like to propose that class methods do not get inherited along normal class lines. I think you're not thinking about many major usage cases for class methods. Actually I have considered many common usages including those which you describe below, and it is my belief that only a few are truly valid uses and not abuses of class method functionality. What I kept coming back to was that pretty much all the *abuses* of class methods were better done in some other way, and that even the *valid* uses were nothing more than design choices, and could be accomplished in some other manner. For one example, look at my Cipher suite. (It's in Pugs's ext/Cipher directory.) The Cipher base class implements most of the visible API, while subclasses simply override a few internal methods; Cipher turns the wide-ranging, convenient external API into a smaller, more easily implementable internal API. Your internal API and your external API have little to do with one another as far as I can tell. The external API is simply a set of convenience functions which create instances of your classes in various ways (very cool ways I might add, especially the functional API, very nice stuff). However, you could easily remove external API, and your internal API would not really suffer, it would only require that the user manually create what your class methods create for you. While many people think Factories are many times overkill (me among them), what you are doing is a perfect candidate for the Factory pattern. In fact, one could say you are already doing an ad-hoc Factory pattern with your inheritable class methods. Some of Cipher's methods are class methods, including the pseudo-procedural .encipher/.decipher and the pseudo-functional .encipherer/.decipherer methods. These methods are included specifically *to* be inherited. Your documentation says the following things: The Cipher API's procedural interface is good enough for many purposes. Although the interface is said to be procedural, it is invoked via two class methods. The Cipher API is fundamentally object-oriented; the procedural and functional interfaces are layers on top of the object-oriented backend. Both indicate to me an acknowledgment that you are knowingly abusing the inheritance of class methods to make your functional and procedural APIs work. Now, please don't take this as an insult or slam of some kind. All good programmers know when to abuse language elements to get what they need. However, I am of the opinion that maybe we should leave these old idioms/abuses aside. In my opinion, class method inheritance is an important part of class-based OO--almost as important as object method inheritance. I disagree with you on this point (of course, otherwise I would not have started this thread), but I will admit that inheritable class methods are a very common OO idiom, and that fact (good or bad) should be taken into account. Removing features simply because their implementation is inconvenient is not The Perl Way. If it were, Perl 6 would be Java With Sigils. To be honest, the implementation is not inconvenient at all, in fact I have already done it twice (correctly at least, the meta-model currently has inheritable class methods, but the implementation is crap). 1) A Mini-MetaModel with Eigenclasses http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ MiniMetaModel_w_eigenclasses.pl Whenever I am doing something which has the potential to dig deeply into the core of the meta-model, I do it first with a Mini-MetaModel. (The MMM (mini-meta-model) is a small self-bootstrapping single- inheritance meta-model in under 2-300 LOC and usually which tends to be much easier to mess with than the real meta-model.) If you look at the new method in Class, you will see it creates an Eigenclass for each class (this is where the class methods get stored), then adding class methods is accomplished with the add_singleton_method method. You will find a number of tests towards the bottom of the file which demonstrate the inheritance of the class methods. 2) By using a subclass of Class http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/t/ 37_inherited_class_methods.t I did this test at autrijus's request, it creates a ClassWithInheritedClassMethods class which is a subclass of Class. If you create your classes (Foo, Bar, what have you) using ClassWithInheritedClassMethods, then you can add class methods, again with the add_singleton_method, and they are inherited correctly by subclasses. The code to make ClassWithInheritedClassMethods work is only 10 lines long, so as you can see the implementation is not difficult or inconvenient at all. To properly implement this in the current meta-model prototype would
Proposal to make class method non-inheritable
Hello all. I would like to propose that class methods do not get inherited along normal class lines. I think that inheriting class methods will, in many cases, not DWIM. This is largely because your are inheriting behavior, and not state (since class attributes are not inheritable). Let me explain in more detail. Let's start by making a very basic definition of an *object*, ignoring any implementation details or specifics. object == state + behavior This statement assumes that *objects* at their core are a unique state coupled with a collection of behaviors to act upon that particular state. Of course we are ignoring all the other class/meta/ inheritence junk for now. To take away the behavior, and only be left with state would degrade our object to the level of C struct or Pascal-style record-type. To take away the state, and only be left with behavior, would basically leave a module/package or some pseudo-random collection of functions. So at this point, I think it is safe to say that an *object* should have both state and behavior. Now, back down from the theoretical cloud to reality. I would like to show some canonical class-method examples (and in some cases, show how they are broken), then show how they might be better accomplished in Perl 6 without the need for class methods to be inherited. == Instance Counting Class The most common example given for class methods is an instance counter. Here is how one might (naively) look in Perl 6: class A { our $.count; method count (Class $c:) { $.count; } submethod BUILD { $.count++; } } Each time an instance of A is created the counter is incremented. So that ... A.count; # 0 A.new; A.count; # 1 Now this makes sense, until we subclass A. class B is A {} A.count; # still 1 B.new; # calls A::BUILD A.count; # 2 B.count; # 2 Clearly, we only have one instance of A, and one instance of B, so those numbers are wrong. It could be argued that since B is a subtype of A, we do have two A's, but the argument does not work in reverse. But either way, I would argue that the results shown above are misleading, and probably not what the programmer intended. What is happening here is that we are inheriting behavior, but not inheriting state. Which goes against the core definition of *objects*. I can solve this, just make class attributes inheritable?, you say. Sure, you could do that, however, it complicates the meta-model unnecessarily. It is much easier to accomplish this using a subclass of Class. class CountingClass is Class { has $.counter; method count (CountingClass $c:) { $.counter; } method new (CountingClass $c: %params) { $.counter++; next; } } class A meta CountingClass {} class B meta CountingClass {} Now A and B both have their own counters neither of which interfere with one another. Of course the meta syntax there is speculative, but surely you can accomplish that behavior somehow. This approach actually uses no class methods, only instance methods. However, as always, there is more than one way to do it, you can accomplish the same thing using Roles. Here is how that might look: role Countable { our $.count; method count (Class $c:) { $.count; } submethod BUILD { $.count++; } } CountingA = A but Countable; CountingB = B but Countable; CountingA.count; # 0 CountingA.new; CountingA.count; # 1 CountingB.count; # 0 CountingB.new; CountingB.count; # 1 NOTE: I am assuming that the Countable role will mix-in the class method count as well as the class attribute $.count. And that A but Countable is really sugar for something like class { does Countable; is A }. == Custom Constructors Another common example of class method usage is custom constructors. This example is moot given the BUILDALL/BUILD system. All class specific initialization can easily be done using custom BUILD submethods. This example too is skewed towards a language's particular object model as well. In Java/C# the constructor is a special/magical thing which is called by the new keyword. In Smalltalk, new is actually an instance method of the class Class, and it calls the specific object's new instance method to initialize (somewhat like the CREATE-BUILDALL/BUILD in Perl 6). In the Perl6-MetaModel prototype, new is implemented as an instance method of Class, and not a class method of Object (as is sometimes assumed). == Java-style static methods Java's static methods are only thought of as being like class methods because they have access to other static class members, and they are only callable though the class. The Perl 6 equivalent of this concept is nothing more than a package sub, and a package variable. Since Class isa Package, this type of behavior is easily accomplished. == Conclusion Now, I am not proposing we abolish class methods entirely, only that we simplify
Re: Proposal to make class method non-inheritable
David, On Oct 11, 2005, at 7:49 PM, Dave Whipp wrote: Stevan Little wrote: I would like to propose that class methods do not get inherited along normal class lines. One of the things that has annoyed me with Java is that it's class methods don't inherit (dispatch polymorphically). This means that you can't apply the template method pattern to static (class) methods. I hope Perl 6 doesn't copy this feature. If you would please give a real-world-useful example of this usage of class-methods, I am sure I could show you, what I believe, is a better approach that does not use class methods. As for Java's static methods, they are very different from class methods in Perl 6. Java's static methods are little more than functions which have access to other static members. This feature is available in Perl 5 now in the form of subs in a package namespace and package scoped variables. The fact that Java uses the method call syntax to access static methods is (IMHO) just an attempt to have consistency in calling conventions. I say this because (as you pointed out) they share very little with other methods. Stevan
Re: Proposal to make class method non-inheritable
David, On Oct 11, 2005, at 8:42 PM, Dave Whipp wrote: Stevan Little wrote: David, ... If you would please give a real-world-useful example of this usage of class-methods, I am sure I could show you, what I believe, is a better approach that does not use class methods. ... The example I've wanted to code in Java is along the lines of: public class Base { public static main(String[] args) { init(); do_it(args); cleanup() } } and then define a bunch of derived classes as my main class. public class Derived extends Base { static init() { print(doing init); } static do_it(String[] args) { print(doing body); } static cleanup() { print(doing cleanup); } } % javac Derived % java Derived In other words, I wanted to not have a main function on the class that I run as the application. This example, of course, doesn't apply to Perl -- but I think that the basic pattern is still useful I think this example is constrained by the way Java handles the main static method. This same pattern could be done using instance methods, and a little bit of reflection in Java. public interface Base { public void init; public void do_it(String[] args); public void cleanup; } public class BaseRunner { public static main (String[] args) { ClassLoader cl = new java.lang.ClassLoader(); Class c = cl.findClass(args[0]); Base b = c.newInstance(); b.init(); b.do_it(args); b.cleanup(); } } public class Derived implements Base { public void init() { print(doing init); } public void do_it(String[] args) { print(doing body); } public void cleanup() { print(doing cleanup); } } NOTE: this code is untested :) This version actually allows you to vary the subclasses though the command line arguments, which provides even greater flexibility and does not require you to recompile BaseRunner or Base. Doing something similar in Perl 6 is even easier than the Java version. Stevan
Class Methods, Eigenclasses and $?CLASS
Evening all, So I am in the process of adding class-methods into the meta-model using eigenclasses. Eigenclasses are a ruby thing (and also a CLOS thing IIRC), in which an anon-class is inserted between an instance and it's class, essentially replacing the instance's class. The anon- class then adds the original class to it's superclass list. This is best shown visually I think: ::Class ^ : -- eFoo is a subclass of Class : ::eFoo # eFoo is also an instance of Class | | -- eFoo is the class of Foo V ::Foo The dispatching of instance methods is still the same, and everything just works. Well... almost everything. There is a slight issue/inconsitency with how $?CLASS works. class Foo { method bar (Class $c:) { $?CLASS } method baz (Foo $self:) { $?CLASS } } Within the bar class-method, the natural inclination is to think that $?CLASS will refer to ::Foo. However, in order to be consistent it actually refers to the eigenclass between ::Foo and ::Class, lets call it ::eFoo. This is because methods are associated with the class which contains them. In the baz instance-method, $?CLASS does refer to ::Foo, since ::Foo is the class which contains baz. It seems to me that this inconsistency could be very problematic, especially since eigenclasses should really be an invisible implementation detail. I am not 100% sure of what is the correct approach here, so I thought I would ask the group. Any thoughts guys/gals? Thanks, Stevan
Re: Class Methods, Eigenclasses and $?CLASS
Luke, On Oct 10, 2005, at 7:47 PM, Luke Palmer wrote: How do you explain this: class Foo { method bar (Class $class:) { class method } } say Foo.bar;# class method my $foo = Foo.new; say $foo.bar; # class method Assuming that that is valid Perl. It is valid Perl 5, however (IMHO) it is *not* valid Perl 6. To start with, the type of the invocant is Class, which $foo is not derived from (it is an instance of something which itself is an instance of Class). I think that $foo.class.bar() should work. And changing the method defintion to be method bar (Class|Foo $class:) { ... } should work, but the code as you wrote it should not. Which means that when we deal with Perl 5 classes within Perl 6, we should likely give them an implied signature of (Class|Foo $self:) or some other weirdness (I haven't thought that far down the line yet). Class methods are strange creatures, in Perl 5 they were nothing different than instance methods. In Java (static methods), they are really just odd functions which need to be qualified by a class name. Python doesn't even really have them (you have to jump through odd hoops to make the method callable). Ruby uses Eigenclasses, and CLOS uses something akin to eigenclasses. I am not sure how Smalltalk handles things, but my guess is that class methods on Foo are instance methods of classFoo, or some such. They are ugly beasties no matter what, but eigenclasses (so far) seem to be the prettiest of the uglies. Stevan
Re: Object Model Pictures
Nathan, On Sep 21, 2005, at 9:02 AM, Nathan Gray wrote: On Tue, Sep 20, 2005 at 08:16:23PM -0400, Stevan Little wrote: http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel2.0/docs/ p6_role_model.jpg I am planning on making Roles self-bootstrapping, so the class(Role) will actually be the first Role in the system. From there, Class will do Role, and Role will do Role. This also means that all the instances of Class will also do Role, which means that classes automatically can also be used as Roles. Thanks for the pictures, Stevan. So every time a class does a new role, a new instance of the class is created as the role. Nope. The Role interface is (for the most part) a subset of the Class interface, well at least the important bits are. So I manually bootstrap the role(Role) into the class(Class), this then means that Class.does(Role). THis means that all instances of Class (all the user defined classes) themselves also do Role. This means that all Classes then become interchangeable with Roles. No new class or role instances need to be created, it is all inherited behavior from the class(Class). If a class does three roles, there will be three role instances of the class, as well as the class' own instance of itself, and a user instance. No, Roles are disposed of once class composition is complete. Part of the class composition process will be to consume any Roles which the class does. THe consumption process takes all the methods and attributes from the Role and actually adds them into the class. After that, the role can essentially be discarded (unless another class uses that same role). When a method is called on the user instance, it asks the class instance if it can do the method, and the class instance looks at the methods in the class, and then at the methods in each role, and dispatches to the appropriate method definition. The dispatch is always in the class since role methods are consumed into the class. A role can be done by several classes at once, because a new instance is created for each class, specific to the class. Methods defined in a class are not clobbered by methods defined in a role. Rather, methods in a role are only catalogued by the class instance if it does not already have a method definition for that name. The order that a class does roles is significant, because if two roles define the same method, only the first one is catalogued by the class instance. Class methods are used first, if the class method is not there, then the Role method is used. If there is a conflict with Role methods, neither Role method is used. By making all conflicts behave this way, we make Role order not-significant. Also If two Role methods conflict, the class consuming the roles must implement that method, otherwise it is a fatal error. Stevan -kolibrie
Re: Object Model Pictures
On Sep 12, 2005, at 3:56 PM, Nathan Gray wrote: Yep, someone needs to make a diagram about Roles, too. Here yah go. http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel2.0/docs/ p6_role_model.jpg I am planning on making Roles self-bootstrapping, so the class(Role) will actually be the first Role in the system. From there, Class will do Role, and Role will do Role. This also means that all the instances of Class will also do Role, which means that classes automatically can also be used as Roles. Here is a mini-meta-model variation which implements this on a very basic level: http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel2.0/docs/ MiniMetaModel_w_Role.pl There is also an ASCII diagram here: http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel2.0/docs/ misc_drawings.txt I was planning on getting Role into the metamodel by the end of this week, but it seems $work might get in the way. Stevan
Object Model Pictures
Hello again. In my never ending quest to implement the Perl 6 object model, I have started drawing pictures. Here is the latest version: http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel2.0/docs/ p6_object_model.jpg (and for OmniGraffle users: http://svn.openfoundry.org/pugs/perl5/ Perl6-MetaModel2.0/docs/p6_object_model.graffle) I would appreciate any comments/questions/suggestions anyone has to offer. A few things to note: - Roles are not yet included in this, I am of the opinion that the core MetaModel should be role-less, and roles will be laid on top of the core metamodel post-bootstrapping. This makes the most sense currently, however, this may change down the road, either way I think it is an implementation detail as long as it looks the same when everything is loaded. - the word meta is used to describe the three-circle items. Please do not read to much into this terminology, meta simply means you should not touch this unless you *really* know what you are doing. Suggestions on better names are welcome. - the reason Foo and $foo are smaller is because they are user created items. Okay, thats all my caveats, fire away please. Stevan
Re: Regarding Roles and $?ROLE
From: Luke Palmer [EMAIL PROTECTED] On 9/11/05, Stevan Little [EMAIL PROTECTED] wrote: Hello all. I have some questions about how Roles will behave in certain instances, and when/where/what $?ROLE should be bound too. 1) Given this example, where 'bar' is a method stub (no implementation) role Foo { method bar { ... } } Should the eventually implemented method still have a binding for $? ROLE? The way you're referring to $?ROLE here sounds kind of akin to asking *the* type (not class) of a particular object. That is, you're asking the compiler for the answer to a question that doesn't make any sense. I do not see $?ROLE as refering to the type of the object, I would think we should use does() for that. I see $?ROLE as being like $?SELF and $?CLASS in that it is just a pseudo-lexical which is only bound in certain situtions (inside a method defintion, inside a class definition, etc). It seems to me that $?ROLE should be bound within a Role defintion as well, and this of course means it is defined within role methods as well. However, method stubs are a grey area. The stub is defined within the Role, and so a part of the Role, but the eventual method defintion is done by the consuming class, which is not part of the Role. Honestly, my vote is for no. I think $?ROLE only really makes sense within the context of the Role, and I am not really sure I see much use for it outside of this anyway. Stevan
Regarding Roles and $?ROLE
Hello all. I have some questions about how Roles will behave in certain instances, and when/where/what $?ROLE should be bound too. 1) Given this example, where 'bar' is a method stub (no implementation) role Foo { method bar { ... } } Should the eventually implemented method still have a binding for $? ROLE? 2) When a Role itself has subroles, which are composed together and consumed by the parent Role, how is $?ROLE bound? is it the top-most Role which it is bound too? or is it bound to the Role it originally came from? Here is an example: role Foo { method foo { $?ROLE } } role Bar { method bar { $?ROLE } } role FooBar does Foo does Bar {} Given this code, does FooBar::foo return FooBar? or Foo? And what about FooBar::bar? This also brings up another question. 3) Using the Roles above, what will this code do? class MyClass does FooBar { method foo { $?SELF.FooBar::foo(); } } Since Roles are flattened, I would think it is reasonable to assume that FooBar::foo exists. However, it does not exists in the concrete in-the-namespace-stash sense. Should fully qualified access to Role methods be mediated by some kind of proxy? Should it actually query a composite Role of some kind? The easy way I think, is to say the above code will fail since FooBar::foo does not exist. However consider for a moment how Role composition works, and how flattening sort of equalizes all the methods and makes ordering unimportant. These qualities are what give Roles such great compositional power, and reduce the complexities/ issues usually associated with mix-ins and multiple inheritance. If you force the user to see the entire Role hierarchy, and not just the topmost Role, are you loosing some of that compositional power? And lastly ... 4) If a Role has a method stub, you are in effect creating a contract with any class which consumes that Role. The class must implement that method. However, what happens if the class consumes another Role which implements that method. Do they still conflict? or does the second Role's version fufill the first Role's contract? Here is a quick code example: role Foo { method foo { ... } } role Bar { method foo { Hello World.say } } class FooBar does Foo does Bar {} Does this work? Does Bar fufill Foo's implied contract? Or is an exception thrown here? Thanks, Stevan
Re: Packages, Modules and Classes
Larry, On Sep 8, 2005, at 2:30 PM, Larry Wall wrote: On Wed, Sep 07, 2005 at 03:00:29PM -0400, Stevan Little wrote: : Also, is there anyway to iterate over the keys in the namespace? The : old way would be to do something like keys(%Foo::). Is something like : this possible with the new way? Sure, it's still just a hash, basically, so Foo.keys() works fine. All we've changed is that we've removed a special syntactic case by allowing a type/package object to pretend to be a hash when used that way, just as we allow it to pretend to be an undef when used as an instance. Tagmemics strikes again... But what if I want to do this? class Foo { my %:stuff; method keys (Class $c:) { %:stuff.keys(); } } How can I get at my namespace now? How would I disambiguiate that call? Doing something like Foo.Package::keys() seems to me to be exposing too much of the meta-level (the Package class). I can see lots of potential conflict between class methods and methods to access the contents of a namespace (methods defined in the Hash role I assume). This means that Foo is getting even more and more magical. It's now a type annotation, a special undef value, the invocant in class methods and the gatekeeper of the namespace. Stevan
Re: Packages, Modules and Classes
Larry, On Sep 8, 2005, at 5:07 PM, Larry Wall wrote: On Thu, Sep 08, 2005 at 04:52:52PM -0400, Stevan Little wrote: : But what if I want to do this? : : class Foo { : my %:stuff; : method keys (Class $c:) { : %:stuff.keys(); : } : } : : How can I get at my namespace now? How would I disambiguiate that call? : Doing something like Foo.Package::keys() seems to me to be exposing too : much of the meta-level (the Package class). : : I can see lots of potential conflict between class methods and methods : to access the contents of a namespace (methods defined in the Hash role : I assume). This means that Foo is getting even more and more magical. : It's now a type annotation, a special undef value, the invocant in : class methods and the gatekeeper of the namespace. Well, like I said, we can require the extra :: in cases of ambiguity. It's really only the misplaced sigil I'm trying to get rid of. So it would be Foo::.keys() then? Would this be possible? my $pkg = Foo::; # or maybe this ... my $pkg = Foo::; Would $pkg be an instance of the Package class? I would assume given this code: package Foo { ... package Foo::Bar { ... } } I can do this: my $pkg = Foo::{'::Bar'} And get back some kind of Package reference of some kind. Do we even have first class packages? h Stevan
Re: Packages, Modules and Classes
Larry, On Sep 7, 2005, at 11:46 AM, Larry Wall wrote: : I base this off the AUTO* hooks described in : S10. I assume too that the METH slot is only valid for Classes, and not : appropriate for Packages and Modules. All those entries are based on the notion of intuiting from the first character of the variable name within the symbol table, not from having separate typeglobbish slots within each symbol. How do I differentiate a method from a sub? Wouldn't they both have the sigil? : class Foo; : has $.baz; : method bar { ... } : : Can I get to $.baz? If I can, what will I get? All sigils and twigils are part of the key to the symbol table, so it's now just Foo$.baz What would Foo$.baz return though (assuming Foo is a class)? It cannot return a value since it is an instance specific value. Should it return some kind of meta-object? Or possibly the default value specified (if one is specified)? Can this value be written too? If so, how does that affect things? Also would/should this work: $iFoo$.baz As a means of breaking the opaque instance data structure. (I for one, vote no on that). - Stevan
Re: Packages, Modules and Classes
Larry, On Sep 7, 2005, at 12:45 PM, Larry Wall wrote: : All sigils and twigils are part of the key to the symbol table, so it's : now just : : Foo$.baz : : What would Foo$.baz return though (assuming Foo is a class)? It : cannot return a value since it is an instance specific value. Foo@baz is not a value either, but a container. I would say that Foo$.baz returns a generic container that happens not to work without an extra instance argument to say which chunk of data to map the container metainfo onto. : Should it return some kind of meta-object? Yes. If methods and subs are in the same namespace, and both have the sigil, what about instance attributes and class attributes? Is this legal? class Foo { my $.bar; has $.bar; } Part of me thinks that it should be since my $.bar is an attribute of the Foo class, and has $.bar is an attribute of instances of Foo. Also, is there anyway to iterate over the keys in the namespace? The old way would be to do something like keys(%Foo::). Is something like this possible with the new way? Thanks, Stevan
Packages, Modules and Classes
Hey all, I recently added Package and Module into the MetaModel (2.0) so that Package is an Object Module is a Package Class is a Module as mentioned here http://article.gmane.org/gmane.comp.lang.perl.perl6.language/4599. Currently Packages have names and Modules add version and authority information, but I have nothing yet in place to represent package symbol tables. Which brings me to my questions. I assume that each symbol table entry has the following slots; SCALAR, ARRAY, HASH, SUB, METH. I base this off the AUTO* hooks described in S10. I assume too that the METH slot is only valid for Classes, and not appropriate for Packages and Modules. This would mean that given this code: package Foo; our $baz; sub bar { ... } %Foo::{'bar'}{SUB} is a ref to the bar sub, and %Foo::{'baz'}{SCALAR} is a ref to the scalar $baz. The same, I would assume, would apply for Modules, so that: module Foo; our $baz; sub bar { ... } is pretty much interchangable with the first example. But I think it's a little trickier when we get to Classes. Given this code: class Foo; our $baz; sub bar { ... } I would expect it to behave just as it does for a Package or Module. But when we start to introduce methods and attributes, I am unsure of how things will work. class Foo; has $.baz; method bar { ... } Can I get to $.baz? If I can, what will I get? I expect that %Foo::{'bar'}{METH} will give me a method ref, but what happens when I try to store something in it? Does that perform some kind of meta-model actions (Foo.meta.change_method(...) or somesuch)? What if I delete the symbol table entry, what happens then (more meta-trickery)? Thanks, Stevan
scopes of $?SELF and $?CLASS
Hello all, I tried to search for this answer in AES12, but I did not see anything, and a perl6.lang search just brought up the whole $_.method vs. ./method debate (which was too much to shlog through). So, onto my question, I am wondering what are the valid scopes for $?SELF and $?CLASS. Are these (magical) globals who only have bound values in certain contexts? If that is so, what value do they have outside of a valid context? undef? or is attempting to accessing the value a runtime exception? Or ... Is it a syntax error to access them outside of a valid scope, and therefore caught at compile time? In this case, then it seems to me that they are not behaving as global variables so much as they are behaving like language keywords. Now as for the valid contexts. The obvious one is that they are both valid within a method. I asumme that $?SELF is bound to the invocant, and $?CLASS is bound to the class the method was defined within. It seems to me that this also mean that in a class method, that $?SELF == $?CLASS? Also (IIRC) we discussed $?CLASS being valid inside a class Foo { ... } block at the hackathon. Would mean that something like this should be possible. class FooLoggerProxy is Foo { has Logger $.logger; for ($?CLASS.meta.superclasses()) - $super { for ($super.meta.getmethods()) - $method { $?CLASS.meta.add_method($method.label = method { $?SELF.logger.log($method.label ~ has been called); return $method.do([EMAIL PROTECTED]) }); } } } I am not sure if there are any other valid contexts other than inside a method or a class composition block. At least none that I can think of. Thanks, Stevan
Re: scopes of $?SELF and $?CLASS
On Aug 17, 2005, at 2:28 PM, Ingo Blechschmidt wrote: Hi, Stevan Little wrote: So, onto my question, I am wondering what are the valid scopes for $?SELF and $?CLASS. Are these (magical) globals who only have bound values in certain contexts? If that is so, what value do they have outside of a valid context? undef? or is attempting to accessing the value a runtime exception? hm, I've thought of these as follows: class Foo {...}# is really class Foo { my $?CLASS := Foo; ...; } method bar($self:) {...} # is really method bar($self:) { my $?SELF := $self; ...; } Yes, this is how I saw it too. The obvious one is that they are both valid within a method. I asumme that $?SELF is bound to the invocant, and $?CLASS is bound to the class the method was defined within. It seems to me that this also mean that in a class method, that $?SELF == $?CLASS? I think so, too. Also (IIRC) we discussed $?CLASS being valid inside a class Foo { ... } block at the hackathon. Would mean that something like this should be possible. class FooLoggerProxy is Foo { has Logger $.logger; for ($?CLASS.meta.superclasses()) - $super { for ($super.meta.getmethods()) - $method { $?CLASS.meta.add_method($method.label = method { $?SELF.logger.log($method.label ~ has been called); return $method.do([EMAIL PROTECTED]) }); } } } I'd opt for yes. I am not sure if there are any other valid contexts other than inside a method or a class composition block. At least none that I can think of. role, submethod? I think in a Role, $?SELF would still be the invocant in a method, and $?CLASS would (eventually) bind to the class the role was composed into. As for submethods, I see them like this: submethod foo () { ... } is really .. submethod foo () { next METHOD unless $?SELF ~~ $?CLASS; } At least that is how larry explained to me about a month ago. Stevan --Ingo -- Linux, the choice of a GNU | Mathematicians practice absolute freedom. generation on a dual AMD | -- Henry Adams Athlon!|
Re: scopes of $?SELF and $?CLASS
Larry, On Aug 17, 2005, at 2:53 PM, Larry Wall wrote: : As for submethods, I see them like this: : : submethod foo () { ... } : : is really .. : : submethod foo () { : next METHOD unless $?SELF ~~ $?CLASS; : } : : At least that is how larry explained to me about a month ago. Can't use ~~ for that, since ~~ implies does, which is not an exact class match. Probably need next METHOD unless $?SELF.class =:= $?CLASS; or some such. In the 2.0 version of the metamodel I compare the class object's .id to the instance's class object's .id. Which is (I assume) how =:= would do it under the hood. Except that BUILDALL/DESTROYALL have to be able to invoke submethods on partial objects whose actual class is not the same as the submethod, so there needs to be some way of forcing $?SELF to consider itself in $?CLASS temporarily for infrastructural purposes. Maybe it's as easy as temp $obj.class := $tmpclass in the BUILDALL/DESTROYALL dispatcher. I dunno. I am not sure if changing classes makes sense here so much as just providing a means for submethod calls to be forced. Currently the metamodels do this by allowing a special parameter in the first argument which is a flag to let the submethod wrapper know if can skip the next METHOD branch. It is a bit of a kludge, but it seems to work. The other option I considered was to make BUILDALL and DESTORYALL special somehow. But I am not sure if this makes any more sense than the kludge described above. Stevan Larry
Re: Perl 6 Meta Object Protocols and $object.meta.isa(?)
Guten Tag Herr Sandlaß, On Aug 9, 2005, at 4:48 AM, TSa (Thomas Sandlaß) wrote: HaloO, 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. --- is subclass of ... is instance of meta(MetaClass) : ^ : : V : MetaClass -+ ^ | : | : | meta(Object)| ^ | : | : | Object --+ 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. - Stevan -- $TSa.greeting := HaloO; # mind the echo!
Re: Perl 6 Meta Object Protocols and $object.meta.isa(?)
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. 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'. Is an object; instance of the 'MetaClass' class Yes sir. That is correct. All in all Stuart, you were pretty much right on. Stevan Thanks, Stuart
Re: Perl 6 Meta Object Protocols and $object.meta.isa(?)
On Aug 9, 2005, at 12:36 PM, TSa wrote: HaloO Stevan, you wrote: Guten Tag Herr Sandlaß, 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
Re: Perl 6 Meta Object Protocols and $object.meta.isa(?)
On Aug 9, 2005, at 10:52 AM, TSa wrote: ~ 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. Yes, TSa is right. Everything below this is Type-stuff and I will leave that to him (up until the Meta part that is). 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? Stevan -- $TSa.greeting := HaloO; # mind the echo!
$object.meta.isa(?) redux
Howdy, I wanted to make sure this question had a chance to get addressed, so I am seperating it from the other thread which has digressed into the depths of the metamodel (much to my delight too). So..., as described in the other thread, 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. Thoughts, Comments, Suggestions? Thanks, - Stevan
$obj.meta.add_method('foo' = ???)
More MOP related questions :) In the p5 MetaModel, you can do the following: $obj-meta-add_method('foo' = Perl6::Method-create_instance_method(sub { ... })); $obj-meta-add_method('foo' = Perl6::Method-create_class_method(sub { ... })); $obj-meta-add_method('foo' = Perl6::Method-create_submethod(sub { ... })); $obj-meta-add_method('foo' = Perl6::Method-create_private_method(sub { ... })); quick aside for clarity The Perl6::Method package is really just a closure generator. It takes a chunk of code (a sub {} ref) and wraps it with the appropriate wrapper based on the type of method-thing you request. It currently handles instance methods, class methods, private methods and submethods. The details of this are not really relevant to this discussion though, I just wanted to answer what I saw as an inevitable question. /quick aside for clarity Now I realize that in perl 6 you can re-open classes and add methods to them. However this is not convenient for programmatic class generation. And I would really prefer the old Perl 5 way of mucking with the symbol table not be the Perl 6 way of doing this. The ideal approach IMO is to be able to do what the p5 MetaModel prototype does, and be able to add methods to the metaclass instance directly (which then exposes them to the class and instances of the class). So, how should this look in Perl 6? I currently have a two thoughts/suggestions/directions. 1) Anonymous methods/submethods $obj.meta.add_method('foo' = method (Foo $self: $bar) { ... });# adding an instance method $obj.meta.add_method('foo' = method (::Foo $class: $bar) { ... }); # adding a class method $obj.meta.add_method('foo' = submethod ($self: $bar) { ... }); # adding a submethod method $obj.meta.add_method(':foo' = method ($self: $bar) { ... }); # adding a private method (NOTE: ':' in name) I am not sure if anonymous methods have been discussed already or not. But this is one possible approach. The idea being that since it is a method already, it would already know about things like $?SELF, $?CLASS and next METHOD (although those values would be unbound), and would likely have an invocant parameter (which could sometimes be used to determine if it was a class method or instance method). 2) Closure factory $obj.meta.add_method('foo' = sub ($self, $bar) { ... }, :typeinstance); $obj.meta.add_method('foo' = sub ($self, $bar) { ... }, :typeclass); $obj.meta.add_method('foo' = ($self, $bar) - { ... }, :typesubmethod); $obj.meta.add_method(':foo' = { ... }, :typeprivate); Given an arbitrary block of executable code (anything from a raw block, to a pointy block, to a sub ref) the add_method closure factory will turn it into the right method-thing based upon the :type parameter. Thoughts?? Thanks, Stevan