Re: txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
--- Larry Wall wrote: > On Tue, Oct 25, 2005 at 05:24:52PM +0200, Michele Dondi wrote: > : But maybe that's just me. Whatever, I guess that the {casual,average} > : programmer may be scared by its richness and complexity. > > But we're trying to design the OO features (indeed, all of Perl 6) > such that you can usefully cargo cult those aspects that are of > immediate interest without being forced to learn the whole thing. > It's not the number one design goal, but it's right up there. Interesting. I just finished reading Stroustrup's thoughts on evolution and language design at: http://www.research.att.com/~bs/rules.pdf and noticed he is similarly concerned about making his language easier for the casual/novice programmer: "If you are a physicist needing to do a few calculations a week, an expert in some business processes involving software, or a student learning to program, you want to learn only as many language facilities as you need to get your job done." He also argues in favour of general features over specialized ones: "C++0x will not be a "Windows language" or a "Web Language" ... " which reminded me of people characterizing Perl as a "text processing language" or a "CGI language". Just as Perl 5 evolved Perl 4 from a "scripting/text processing language" to a general purpose one (with CPAN modules filling many specialized niches), Perl 6 seems to be evolving still further down that path, being applicable to more and varied domains than Perl 5 was. /-\ Send instant messages to your online friends http://au.messenger.yahoo.com
Re: txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
On Wed, Oct 26, 2005 at 09:36:48AM +0200, Michele Dondi wrote: : On Tue, 25 Oct 2005, Larry Wall wrote: : : >But we're trying to design the OO features (indeed, all of Perl 6) : >such that you can usefully cargo cult those aspects that are of : >immediate interest without being forced to learn the whole thing. : >It's not the number one design goal, but it's right up there. : : So you're talking about a "positive", tame form of cargo cult, giving the : latter a good name... Yes, I hack on more languages than just Perl. :-) I use the term "cargo cult" for lack of a better term, and when I do so I tend to use it as a verb rather than a noun. By "cargo culting" I mean the process by which most of us learn to use new technology. We appropriate inappropriately; we have to start using a thing wrongly before we can start using it rightly. When we're very young, we learn by picking up objects and stuffing them into our mouths. That's not the appropriate way for an adult to treat most objects, but it's the right way for a toddler to treat an object, and it's the parents' responsibility to "child-proof" the room so the child doesn't chew on power cords and such. So another way to say what I said is that we're trying to make Perl 6 relatively safe for people who are just starting to use bits of it inappropriately in order to learn it. The term "cargo cult" also has some religious connotations, and to a small extent I mean those too. The "religious" wars fought in computer communities often arise among those with the least understanding of the deep issues. People much more easily fall into tribal behavior than into philosophical behavior. A deep understanding of bikesheds is that they're meant to hold bicycles, and it doesn't really matter what color they are. But when you first discover a bikeshed, you might mistake it for a tribal monument of some sort. It's obviously more important than the bicycle; after all, it's bigger. And we might attract more new husbands or wives from other tribes if we paint it attractively. So we spend a lot of time painting the outside while the bicycle is inside rusting. And the bicycle is what's important, because we should be reaching out to other tribes, not waiting for them to come to us. Well, hey, my metaphor is probably painted the wrong color. But maybe it's only by using analogies inappropriately that we can begin to understand how to use them appropriately. Larry
Re: txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
On Tue, 25 Oct 2005, Larry Wall wrote: But we're trying to design the OO features (indeed, all of Perl 6) such that you can usefully cargo cult those aspects that are of immediate interest without being forced to learn the whole thing. It's not the number one design goal, but it's right up there. So you're talking about a "positive", tame form of cargo cult, giving the latter a good name... Michele -- you need a brain hack. or a brain of any sort. try a nematode first. the small incremental improvement won't be such a shock. then you can graduate to segmented worm brains. - Uri Guttman in clpmisc, "Array Sort Using Regex Matching Fails"
Re: txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
On Tue, Oct 25, 2005 at 05:24:52PM +0200, Michele Dondi wrote: : Also, Perl6 OO capabilities are already above the top of my head. Sure, they're above my head too. Which should be obvious by now... :-) : But maybe that's just me. Whatever, I guess that the {casual,average} : programmer may be scared by its richness and complexity. But we're trying to design the OO features (indeed, all of Perl 6) such that you can usefully cargo cult those aspects that are of immediate interest without being forced to learn the whole thing. It's not the number one design goal, but it's right up there. Larry
Re: txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
On Tue, 25 Oct 2005, Stevan Little wrote: 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. ack! 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. I see your point. And I admit I slightly misunderstood you. In any case people who don't know Perl and think it's great for text processing may be eventually become interested in it if they will have to do... ehm... text processing. But even if Perl will gain a name for it's "cool OO features", will it become an actual interest for someone if he/she has to do... OO stuff?!? The basic idea being that one is attracted by a language or another if its features are well suited for some specific application he/she has in mind. Not for its features as an abstract thing. Also, Perl6 OO capabilities are already above the top of my head. But maybe that's just me. Whatever, I guess that the {casual,average} programmer may be scared by its richness and complexity. 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) Of Perl is IMHO even _too_ known for CGI. 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. ack. I was oversimplifying. 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. Also, some methods will be very handy even for non-patently-OO blocks, e.g. the .pos() one which will replace the somewhat ad hoc pos() function or the .subst() one (or whatever it is called, I can't remember exactly) which hopefully will get rid of the "why doesn't s/// work inside a map()" question... Michele -- Have you ever stopped to consider that what is crashing your Perl is sitting between the keyboard and chair? - Sherm Pendley in clpmisc, "Re: Perl IDE" (edited)
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
txt vs OO [was: "Re: Proposal to make class method non-inheritable"]
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. 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, but "OO programming" is somewhat immaterial either, the "only" relevance being the suitability for big projects management. Michele -- Ira Kane: If I was a giant nasty alien bird in a department store, where would I be? Harry Block: Lingerie. Ira Kane: Not you, the bird. Harry Block: Lingerie. - "Evolution", Ivan Reitman
Re: Re(vised): Proposal to make class method non-inheritable
On Wed, Oct 19, 2005 at 04:03:54AM -0700, Larry Wall wrote: > : This one is new to me. I'm not sure I understand what it's used for. Is > : there already some documentation about it? > > It's in my copy of S06, which I haven't checked in yet. Is there an AES commit feed available somewhere? -- Gaal Yahas <[EMAIL PROTECTED]> http://gaal.livejournal.com/
Re: Re(vised): Proposal to make class method non-inheritable
Larry Wall skribis 2005-10-19 4:03 (-0700): > The absence of a dot creates a private attribute. We decided it should > be even easier to declare a private attribute than a public one, so it's > just > has $foo; > and then it is visible only in the lexical scope. This takes away my objections to the dot twigil entirely. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Re(vised): Proposal to make class method non-inheritable
On Wed, Oct 19, 2005 at 12:33:11PM +0200, Juerd wrote: : > : make $:foo equivalent to :foo($foo) (conjectural) : : This one is new to me. I'm not sure I understand what it's used for. Is : there already some documentation about it? It's in my copy of S06, which I haven't checked in yet. By the way, the form is intended to work in either signatures or as an rvalue, and in signatures replaces + to mark named args. + becomes the marker for required attributes (assumed on initial positional args). : And does this mean $:foo is no longer a private $.foo? (which could be a : very good thing, by the way) What replaces that? The absence of a dot creates a private attribute. We decided it should be even easier to declare a private attribute than a public one, so it's just has $foo; and then it is visible only in the lexical scope. Larry
Re: Re(vised): Proposal to make class method non-inheritable
Larry Wall skribis 2005-10-19 1:43 (-0700): > On Tue, Oct 18, 2005 at 04:43:57PM +0200, Juerd wrote: > : dot sigils are not actually special. They are required on has-variables > : and forbidden on all other. Changing them to be optional is trivial, or > : so I hope. > Dot sigils drive accessor generation, which essentially hoists an > ordinary variable into the object's namespace. They are not just > commentary. "has" can do this without the dot, in theory. > : (I believe that sigils or twigils should not indicate scope, duration or > : type. The distinctin between the major variable types is useful, further > : distinction is not.) > Eh? Sigils are for type, twigils are precisely for doing weird things > with scope or duration. This doesn't change how I feel about them, though :) Still, I do like twigils for automatically existing variables, like %*ENV and &?SUB. Here, I do see the need and use for indicating scope and duration, but I mostly read the twigil as: this variable is /special/. Global scope needs a twigil because in most cases, the declaration would be nowhere to be found. Declaring superglobals doesn't necessarily make sense anyway. The ^ twigil is needed for the same reason: declaration is implicit. Object attributes are declared by the Perl coder and initialized by code. I know where they come from, and if not, I can look it up very easily. There is no twigil for "my" and "our" variables, and we don't need any. Same for "has": declaration is explicit. > : make $:foo equivalent to :foo($foo) (conjectural) This one is new to me. I'm not sure I understand what it's used for. Is there already some documentation about it? And does this mean $:foo is no longer a private $.foo? (which could be a very good thing, by the way) What replaces that? Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Re(vised): Proposal to make class method non-inheritable
On Tue, Oct 18, 2005 at 04:43:57PM +0200, Juerd wrote: : dot sigils are not actually special. They are required on has-variables : and forbidden on all other. Changing them to be optional is trivial, or : so I hope. Dot sigils drive accessor generation, which essentially hoists an ordinary variable into the object's namespace. They are not just commentary. : (I believe that sigils or twigils should not indicate scope, duration or : type. The distinctin between the major variable types is useful, further : distinction is not.) Eh? Sigils are for type, twigils are precisely for doing weird things with scope or duration. * global scope + currently compiling scope ? currently compiled scope = current file/pod scope < current $/ scope ^ current signature scope : make $:foo equivalent to :foo($foo) (conjectural) Larry
Re: Re(vised): Proposal to make class method non-inheritable
[EMAIL PROTECTED] wrote: U... I'm not sure that allowing $. injection from the nested blocks is a good thing. I don't think it's ambiguous, but to me it looks weird and confusing - if a user put the variable in the nested block like that, it's almost certain he actually meant to write { my $foo; } and the . was put there erroneously. Gack, furthermore, I was thinking 'has' and reading/writing 'my'. Sorry. :( 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? Well, if it belongs to the module part of the class, the syntax would be Bar::method(...), right? Yes, but the . is the method invocation operator, the :: is package symbol table access. I think they really mean different things. Yes. Now to be literal-minded, if Foo is a class... Foo::method() would mean package(Foo)::method() (do package access, call method. No invocant, but you can access the proper child of Foo as $*MODULE) Foo.method() would mean Class::method(Foo:) (forward to metaclass, with class as an invocant) Nicely symetric, and (IMHO) completely unintuitive. So what exactly means to say that a class is a module? This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. Well, namespaces should generally be inheritable. I don't think this is true, this is a Perl 5-ism. How else would lexical namespaces inject variables from outer block into the inner? I think you are confusing namespacing with scoping. The scope rules are as such that the inner can access see the outer. Fair enough. I was talking about implementation - this means you need symbol table import and shadowing (with the symbols defined in the inner scope). Same (or similar) policy could be used for class methods and attributes. I guess at the package level declaration that Class1 is Class2 would just inject symbols from one module into the other? (yes, this is kinda handwavy :/ ) I don't think this would be so, unless you explicitly asked for it. I'm not sure I understand, why not? Anyway, this makes me cringe on a certain level, although I'm not sure I can put the reason into words. Strictly speaking, it's bad only if there are cases where multimethod should behave differently for a class and an instance. One case I can think of is class AutoCreation { ... }; multi dwimmy_instance(class AutoCreation $obj) { $obj.new() } multi dwimmy_instance(AutoCreation $obj) { $obj } I think we need some ability to differentiate between the class version of Foo and the instance version of Foo. I think we agree here. :) Miro
Re: Re(vised): Proposal to make class method non-inheritable
On Tue, 2005-10-18 at 10:16 -0400, Stevan Little wrote: > On Oct 18, 2005, at 6:56 AM, Miroslav Silovic wrote: > > Uhm. I'm not sure either. :) The way I read Larry's mail, > > multimethods use .isa operator to detect whether $foo belongs to > > Foo. And for every class, Foo.isa(Foo) is true (this is exceptional > > behaviour of .isa). So > (sidebar: it will probably use .does actually, but this an as yet > unresolved detail) Consider it fairly resolved. (What? Using type as a marker of potential coercion? Yep!) -- c
Re: Re(vised): Proposal to make class method non-inheritable
Stevan Little skribis 2005-10-18 10:16 (-0400): > You are probably right, but are the twigils actually special? or is > it just a naming convention. dot sigils are not actually special. They are required on has-variables and forbidden on all other. Changing them to be optional is trivial, or so I hope. (I believe that sigils or twigils should not indicate scope, duration or type. The distinctin between the major variable types is useful, further distinction is not.) > I don't think this is true, this is a Perl 5-ism. Perl 5 isn't a synonym for "bad". "Perl 5-ism" can be construed as positive or negative. Please do elaborate. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: Re(vised): Proposal to make class method non-inheritable
On Oct 18, 2005, at 6:56 AM, Miroslav Silovic wrote: Disclaimer: I don't ~~ @larry :) [EMAIL PROTECTED] wrote: 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). U... I'm not sure that allowing $. injection from the nested blocks is a good thing. I don't think it's ambiguous, but to me it looks weird and confusing - if a user put the variable in the nested block like that, it's almost certain he actually meant to write { my $foo; } and the . was put there erroneously. You are probably right, but are the twigils actually special? or is it just a naming convention. 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? Well, if it belongs to the module part of the class, the syntax would be Bar::method(...), right? Yes, but the . is the method invocation operator, the :: is package symbol table access. I think they really mean different things. This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. Well, namespaces should generally be inheritable. I don't think this is true, this is a Perl 5-ism. How else would lexical namespaces inject variables from outer block into the inner? I think you are confusing namespacing with scoping. The scope rules are as such that the inner can access see the outer. I guess at the package level declaration that Class1 is Class2 would just inject symbols from one module into the other? (yes, this is kinda handwavy :/ ) I don't think this would be so, unless you explicitly asked for it. I am also not sure what you mean about multi-methods either, could you please explain more? Uhm. I'm not sure either. :) The way I read Larry's mail, multimethods use .isa operator to detect whether $foo belongs to Foo. And for every class, Foo.isa(Foo) is true (this is exceptional behaviour of .isa). So (sidebar: it will probably use .does actually, but this an as yet unresolved detail) multi bla (Foo $f); would accept both bla(Foo.new()) and bla(::Foo). (Larry, please correct me on this if I'm misparaphrasing you :) ) I am not 100% sure this is true given basic multi-method behavior, however there is no reason we cannot either special case this, or do some other kind of trickery to make it happen. Anyway, this makes me cringe on a certain level, although I'm not sure I can put the reason into words. Strictly speaking, it's bad only if there are cases where multimethod should behave differently for a class and an instance. One case I can think of is class AutoCreation { ... }; multi dwimmy_instance(class AutoCreation $obj) { $obj.new() } multi dwimmy_instance(AutoCreation $obj) { $obj } I think we need some ability to differentiate between the class version of Foo and the instance version of Foo. Stevan
Re: Re(vised): Proposal to make class method non-inheritable
Disclaimer: I don't ~~ @larry :) [EMAIL PROTECTED] wrote: 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). U... I'm not sure that allowing $. injection from the nested blocks is a good thing. I don't think it's ambiguous, but to me it looks weird and confusing - if a user put the variable in the nested block like that, it's almost certain he actually meant to write { my $foo; } and the . was put there erroneously. 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? Well, if it belongs to the module part of the class, the syntax would be Bar::method(...), right? This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. Well, namespaces should generally be inheritable. How else would lexical namespaces inject variables from outer block into the inner? I guess at the package level declaration that Class1 is Class2 would just inject symbols from one module into the other? (yes, this is kinda handwavy :/ ) I am also not sure what you mean about multi-methods either, could you please explain more? Uhm. I'm not sure either. :) The way I read Larry's mail, multimethods use .isa operator to detect whether $foo belongs to Foo. And for every class, Foo.isa(Foo) is true (this is exceptional behaviour of .isa). So multi bla (Foo $f); would accept both bla(Foo.new()) and bla(::Foo). (Larry, please correct me on this if I'm misparaphrasing you :) ) Anyway, this makes me cringe on a certain level, although I'm not sure I can put the reason into words. Strictly speaking, it's bad only if there are cases where multimethod should behave differently for a class and an instance. One case I can think of is class AutoCreation { ... }; multi dwimmy_instance(class AutoCreation $obj) { $obj.new() } multi dwimmy_instance(AutoCreation $obj) { $obj } (I pulled the syntax out of my nose for this). Anyhow, this looks like a pretty contrieved usage. I'm still trying to think of a non-contrieved, more realistic situation when you might actually want something like this. Miro
Re: Re(vised): Proposal to make class method non-inheritable
On Oct 17, 2005, at 12:32 PM, TSa wrote: 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? Symmetric MMD at least has the meaning that the above mentioned asymmetry doesn't exist for infix ops on the syntactic level: $x foo $y; which neither means ($x foo) $y; # calculated prefix op from postfix foo nor $x (foo $y); # calculated postfix op from prefix foo. I can't speak for metric MMD, though. But IIRC, the metric is 'sum of superclass hops'. -- Okay, I think I understand now. So if all class methods were multis, then we would not need inheritance. The MMD would use the (super|sub) class relationships, and be able to call (super|sub)classes automagically. However, IIRC, the "everything is a multi-method" proposal was not accepted. Could this then be just a restricted case of multi-methods? So all class methods would just use MMD dispatch rules on the invocant parameter, therefore allowing an implicit pseudo-inheritence to take place? Larry, is this what you were thinking? Stevan
Re: Re(vised): Proposal to make class method non-inheritable
HaloO, Stevan Little wrote: 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? I think not. But the current notion seems to drift closer to my idea of "free methods" versus "slot calls". To express that in therms of your initial equation object == state + behavior would be expressed on the first meta level as class == data(structure) + code(structure) which means that the compiler syntactically splits the class definition into an active and a passive part. Call this symmetry breaking if you like. The same asymmetry exist in the method call syntax $foo .action; because the compiler compiles that into a lookup of 'action' from the method part of the MIR (Meta Information Repository, World in Russian) followed by a dispatch on the actual runtime type referred to by $foo. In other words, the name that connects the compile and runtime is 'action'. If this name shall be retrieved from the instance at runtime without going through the method dispatcher I have proposed to wrap-up the name as $foo :action; Without the $ sigil a bare foo is interpreted as a name lookup in the code part of the MIR which is the union of all subs and methods---subs beeing nullary methods so to speak. That gives foo .action; # dispatch action on retval of foo and foo :action; # bind named param in the call to foo. These two things are on the tightest precedence level, which in my eyes makes . and : meta sigils or some such. We could actually combine these with the idea of the current name beeing a sigilled underscore and '_._' denoting the current method on the current topic, and '_:_' the current key from the current topic :) Hmm, these would make {_} the closure of the current continuation or so. 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? Symmetric MMD at least has the meaning that the above mentioned asymmetry doesn't exist for infix ops on the syntactic level: $x foo $y; which neither means ($x foo) $y; # calculated prefix op from postfix foo nor $x (foo $y); # calculated postfix op from prefix foo. I can't speak for metric MMD, though. But IIRC, the metric is 'sum of superclass hops'. --
Re: 'self' and .foo (was: Re: Re(vised): Proposal to make class method non-inheritable)
On 2005-10-15 15:28, "Ilmari Vacklin" <[EMAIL PROTECTED]> wrote: > On Sat, Oct 15, 2005 at 09:49:30AM -0700, Larry Wall wrote: >> On Sat, Oct 15, 2005 at 07:39:36PM +0300, wolverian wrote: >> : IMHO just call it "self" (by default) and be done with it. :) >> >> Let it be so. > > Somewhat off-tangent: does this mean that .foo is always $_.foo? INCOMING!! . . . Hunh. Who'da thunk - apparently even *flame* wars can trigger post-traumatic stress disorder...
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
[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. 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. Larry's proposal is to remove that difference for multimethods. Personally I can't think of a good objection to that idea (except if it may be bad for performance - is there a plan to infer types and auto-inline? I that case, declaring that you don't care about instance part of the object's functionality can really help). Miro
'self' and .foo (was: Re: Re(vised): Proposal to make class method non-inheritable)
On Sat, Oct 15, 2005 at 09:49:30AM -0700, Larry Wall wrote: > On Sat, Oct 15, 2005 at 07:39:36PM +0300, wolverian wrote: > : IMHO just call it "self" (by default) and be done with it. :) > > Let it be so. Somewhat off-tangent: does this mean that .foo is always $_.foo? > Larry -- Ilmari Vacklin
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: 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
On Sat, Oct 15, 2005 at 07:39:36PM +0300, wolverian wrote: : On Sat, Oct 15, 2005 at 08:25:15AM -0700, Larry Wall wrote: : > [snip] : > : > Of course, there's never been any controversy here about what to call : > "self", oh no... :-) : : IMHO just call it "self" (by default) and be done with it. :) Let it be so. Larry
Re: Re(vised): Proposal to make class method non-inheritable
On Sat, Oct 15, 2005 at 08:25:15AM -0700, Larry Wall wrote: > [snip] > > Of course, there's never been any controversy here about what to call > "self", oh no... :-) IMHO just call it "self" (by default) and be done with it. :) -- wolverian, contributing to the general disagreement
Re: Re(vised): Proposal to make class method non-inheritable
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 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. 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. (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... :-) : >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. Larry
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, 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: Re(vised): Proposal to make class method non-inheritable
On Fri, Oct 14, 2005 at 01:43:39PM +1100, Stuart Cook wrote: : On 14/10/05, Stevan Little <[EMAIL PROTECTED]> wrote: : > 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 B&D) : > : >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. : : How about: : : method bark (Dog ::K:) { ... } : : Where ::K must hold a class that is a subclass of Dog. Or 'is a : subtype of', or 'does', or whatever the most correct term is in this : context. 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. But we have to think a bit more about the notion of currying class objects into real objects, or something approaching real objects. 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. Larry
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
Re: Proposal to make class method non-inheritable
Stevan Little <[EMAIL PROTECTED]> writes: > 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. 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? And you're using a deliberately broken example as grist to your mill? Doesn't sound all that Perlish to me. -- Piers Cawley <[EMAIL PROTECTED]> http://www.bofh.org.uk/
Re: Re(vised): Proposal to make class method non-inheritable
On 14/10/05, Stevan Little <[EMAIL PROTECTED]> wrote: > 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 B&D) > >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. How about: method bark (Dog ::K:) { ... } Where ::K must hold a class that is a subclass of Dog. Or 'is a subtype of', or 'does', or whatever the most correct term is in this context. (I seem to recall Damian mentioning something like this on the list somewhere, but I might have misunderstood him and made it up myself.) I do notice, though, that most of these class-method forms don't stand out very well--maybe something like 'classmethod' might be best after all, particularly if class methods aren't heavily used. Stuart
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 B&D) 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
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: Proposal to make class method non-inheritable
HaloO, Stevan Little wrote: On Oct 11, 2005, at 8:47 PM, Larry Wall wrote: 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. I love this notion because that makes the type that the class represents the potential state it would reach when *all* distinguishable instances were realized---which needs a lot of memory for many classes. But the bit class/type e.g. has exactly two distinguishable states! Well and more then these two will never be needed if the algebraic, boolean type is build with !, && and ||. Negation just exchanges the half of the type that is in use, the former one is returned into potentiality, that is, it leaves the programs actuality. The binary connectives leave false and true in the program respectively as soon as both booleans have entered the program! That is (1 && 0 == 0) and (0 || 1 == 1) dual each other, just as the unrealized potential state of a class duals the actually realized state of the instances of the class in any particular moment. Here's a nice magic square picture of the idea: -Class .. ::Classmeta space ** | /| | / |The diagonal line splits the potential(-) from | / |the actual(+) instances. Undef and the ::Class |/ |are the "singularities" of the class. The state | /|of the class moves up the diagonal through instance | / |creation, while the GC moves it towards Undef. | / | ** Undef .. +Classvalue space 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. --
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 pr
Re: Proposal to make class method non-inheritable
All - I'm partly to blame for this thread because I put the idea into Steve's head that class methods being inheritable may be dogma and not a useful thing. Mea culpa. That said, I want to put forward a possible reason why you would want class methods to be inheritable - to provide pure functions. If we go back to every function/method/subroutine being behavior, it's pretty evident that you need some state for that behavior to operate upon. In a procedural function, the state is provided. In an object, that state is both provided and inherent in the instance the method is operating upon. In functional languages, functions maintain their own state through closures, continuations, and the like. I might want to provide in a base class a set of useful sorting routines or other such items. These would be true procedural functions and there would be a warning thrown if it accessed class state. Rob
Re: Proposal to make class method non-inheritable
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. 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. 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. In my opinion, class method inheritance is an important part of class-based OO--almost as important as object method inheritance. Removing features simply because their implementation is inconvenient is not The Perl Way. If it were, Perl 6 would be Java With Sigils. -- Brent 'Dax' Royal-Gordon <[EMAIL PROTECTED]> Perl and Parrot hacker
Re: Proposal to make class method non-inheritable
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? 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
On Wed, 2005-10-12 at 12:00 -0400, Stevan Little wrote: > Usefulness aside, why do Roles and Classes need to be seperate > beasts? In the current meta-model prototype, the role system is laid > atop the class system so that the following is true: > > Class is an instance of Class > Role is an instance of Class > Class does Role > > This then means that Role also .does Role since Role is an instance > of Class (which does Role). > > It gets very cyclical, but it essentially means that all classes can > be treated as roles. This allows for all sorts of interesting things > to happen actually. I've always thought that classes were more specific than roles in that you can't apply a class to another class. (Maybe that's the wrong direction of specificity. Though I am positive that .does() is more general than .isa(), I always have to stop and think about which direction co- and contra-variance goes.) Certainly I think declaring a class should imply a role of the same name, even if you can't actually apply that role and mix in state and behavior. > I have to admit though, that this comes directly from Scala (so maybe > we are not alone here out on the edge :) I've also heard that Sather does something similar but don't know any details. -- c
Re: Proposal to make class method non-inheritable
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; } That more or less robs the constructor of the "behavior" part of "class = state + behavior." I need an opportunity to establish my invariants. 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. 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.) 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. 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, 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'll leave the probably obvious role-based interpretation of this to those versed in such. :) And I'm going to shut my yap, now, having butted into the middle of a discussion of a hopelessly complex runtime that I haven't been following for a 18 months. :) — 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
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
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 invocan
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
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, 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 con
Re: Proposal to make class method non-inheritable
Stevan Little <[EMAIL PROTECTED]> writes: > 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. We definitely have two instances of A since, B.isa(::A). We also have a fragile implementation of count. 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)} 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
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.) : 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. 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 ... } Rather than having to make plugin creation cheap so that I can do this: class Host { public Type PlugInClass { get { ... } set { ... } } } class PlugIn { public bool Host { get; } public abstract bool SupportsFeatureB { get; } public abstract bool SupportsFeatureA { get; } } ... later ... PlugIn plugIn = (PlugIn) Activator.CreateInstance(host.PlugInClass); if (plugIn.SupportsFeatureA) { ... expose UI element ... } Another alternative is to introduce a PlugInFactory. Which might be better in complex scenarios. But it's often overkill. And it's certainly more typing. In C#, I might also use attributes to decorate the plugin Type. But those, too, are more typing than class methods (and also weakly typed). Also, of course, inheriting constructors is nice. Of course, it opens up the whole "designated constructor" can of worms. But that's okay; if you're subclassing, it's your responsibility to make it work -- Gordon Henriksen [EMAIL PROTECTED]
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
Re: Proposal to make class method non-inheritable
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. : 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. 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. : 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++; : } : } 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. 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. : 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. 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. : 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... :-) : What is happening here is that we are inheriting behavior, but not : inheriting state. Which goes against the core definition of *objects*. I'd say that state is precisely what we're inheriting here. It's just the state of something that is not the object. But that was already true of class A as well. : "I can solve this, just make class attributes inheritable?", you say. Don't see how that would help, unless you also force every class to redeclare the attributes. (By the way, attributes of the form $.count are already inheritable, being shorthand for $?SELF.count.) : 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 get
Re: Proposal to make class method non-inheritable
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
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
Damian, On Oct 11, 2005, at 6:53 PM, Damian Conway wrote: Anyway, I have said my peace, what do you all think? I think there are serious problems with this proposal. For a start, it would be very difficult to create *any* objects at all if the C class method wasn't inheritable. Actually &new should be an instance method of Class, not a class method of Object. Since all classes are instances of Class, then calling Foo.new is just calling an instance method on the instance of Class whose name is Foo. As for overriding a class specific &new, this is accomplished using singleton-methods on the instance of Class. That &new is then not inherited. I think that this is probably sane, and the BUILD submethod is a far better place to put class specific initialization since your are guaranteed to have all BUILD methods run correct and in-order. This follows how most other reflective object models work. In Smalltalk-80 every class has a metaclass, the class itself stores all instance methods for the instance, while the metaclass stores all "class methods" (which are basically instance methods on the metaclass instance). This allows the smalltalk method dispatcher to work exactly the same for both class methods and instance methods. Smalltalk does allow you to define the "new" message for a particular class, but it becomes an instance method of the metaclass. In CLOS, the generic method 'make-instance' is specialized to 'standard-class', it runs the initializer of each superclass in the class precedence list, but those are instance specific methods. Ruby uses singleton-methods on the Class instance to create "class methods", which is where the whole eigenclass thing comes from. The result is that class methods are themselves instance methods on the eigenclass (which is very similar to how Smalltalk's metaclass system works). Also in most of the other literature I have read, the responsibility of creating an instance is relegated to Class, and not to Object (or some other element of the system). Stevan
Re: Proposal to make class method non-inheritable
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".
Re: Proposal to make class method non-inheritable
Anyway, I have said my peace, what do you all think? I think there are serious problems with this proposal. For a start, it would be very difficult to create *any* objects at all if the C class method wasn't inheritable. Damian
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, on