Re: class interface of roles
HaloO, Jonathan Lang wrote: Still not following. Can you give an example? The example in the original post contains a class GenSquare that has got an equal method that checks the sides of the self square and the incoming argument square. The GenPointMixin role provides an equal method that compares the x and y coordinates. The correct final method equal of the composed class needs to check sides and coordinates. If the simple side checking equal of the class overrides the closure from the role there is a false implementation. OTOH, forcing all classes to call the role closure is bad design of the composition process. Hence I'm arguing for a super keyword that in a role refers to the class. In the example super.equal($p) calls the side checking closure. Note that it's entirely possible for attributes to not make it into the final class, if the accessor methods get redefined in such a way as to remove reference to the attributes. This is part of the notion that roles supply an outline of what the class should do, but only the class actually supplies the definitive details of how to do it. I see that you regard the class as the ultimate definer of functionality. The role requires a method including its signature but the class implements it. For the type system the role encodes the guarantee of the method availability. As I see it: is and does declarations in a role impose requirements on the final class: it must derive from another class (is), or it must compose another role (does). method and has are each one part requirement and one part suggestion: for method, the class is required to include a method that matches the given name (which, of course, includes the method's signature), and a particular closure is suggested that the class can accept or override. I almost agree here. The only thing I'm asking for is that the role's closure is not discarded so easily. The designer of the role takes responsibility for the role's part in the final method closure. The combination process should produce the correct result automatically and independent of the class's cooperation. Thus, the only things that I'd recommend using to calculate a type-boundary would be the superclasses (provided by is) and the method names (provided by method and has). That makes classes too typeish. The type system is mostly based on roles. The class inheritance graph should not be used for typing. Or do you want constraints on the class derivation process that guarantees subclasses to be subtypes? As I read it the class derivation is free to violate replaceability of subclasses where superclasses are expected. Roles are a guarantee of functionality not classes. I agree with the idea behind the current definition of this: if the class provides its own definition for a method, that should take precedence over the role's definition. If it doesn't, then it adopts the role's definition as its own. I would hope it is the role if a as of now unknown syntax has declared it. Perhaps it should be even the default. The rational for my claim is that a role is composed several times and then every class doing the role automatically gets the correct version. Otherwise all classes are burdened with caring for the role's part in the method. Huh? Yeah! The role adds a certain aspect to the correct implementation of a method. And so does the class. But it is the role that is composed into the class not the other way around. A role is intended to be composed several times into completely different classes. With blind precedence to class methods the role's aspects are lost and have to be reintroduced in each and every class. I consider that inconvenient and error prone. It should assume that if Foo overrides A's implementation of blah, Foo knows what it's doing; by the principle of least surprise, Foo should never end up overriding A's implementation of blah only to find that the original implementation is still being used by another of the methods acquired from A. Could you make an example because I don't understand what you mean with original implementation and how that would be used by role methods. role A { method foo() { say Ah... } method bar() { $self.foo() } } Isn't that self.foo() without the sigil? It is clear that .foo is dispatched on the class. [..] class Baz { method foo() { $self!'A::foo'(); say Choo!; } method bar() { $self.foo() } method baz() { $self!'A::foo'() } my method 'A::foo'() { say Ah... } } What is A referring to here? Baz doesn't compose role A here. And why the exclamation mark? In Baz, Cmy method 'A::foo'() represents the original implementation of foo(), while Cmethod foo() represents the final implementation chosen by the class. OK, thanks for the example. If you were to allow a role method to directly refer to its own implementation, you could do something like: role A { method foo() { say Ah... }
Re: Runtime role issues
Paul Seamons wrote: On closer inspection, is it even possible to add a Role to a Class at runtime? If it isn't now, I would certainly like to have a hook available through MOP (which is, to the best of my knowledge, still unspecified). I thought that Class and Role composition outside of compile time resulted in a new pseudo Class for the subsequent instances of that composition - in which case the original Class would remain unmodified. I believe 'does' and 'but' operators work that way, yep. Additionally, they're per instance. Offhand I don't even recall any way to create an uninstantiated class with a role mixed at runtime (would my $class_foobar = ::Foo but ::Bar do the trick?) Miro
Re: class interface of roles
TSa wrote: HaloO, Jonathan Lang wrote: Still not following. Can you give an example? The example in the original post contains a class GenSquare that has got an equal method that checks the sides of the self square and the incoming argument square. The GenPointMixin role provides an equal method that compares the x and y coordinates. The correct final method equal of the composed class needs to check sides and coordinates. If the simple side checking equal of the class overrides the closure from the role there is a false implementation. Actually, the correct equal method for the composed class needs to check the sides of the square, because how the class defines it: in this example, class GenSquare _is_ the final class, and so whatever method it provides _is_ the final method, for good or ill. If this results in other method definitions inherited from GenPointMixin behaving strangely, then GenSquare needs to override those methods as well. Mind you, the above implies a radical shift in the underlying semantics, akin to having class Dog compose role Tree and redefining method bark() to suit its own nature. Proper use of role composition is to refine the role's underlying concept, not to radically alter it. Even if we were to go with a modified version of the original example, where GenSquare is a role and both GenSquare and GenPoint are being composed into a final class - say, GenPositionedSquare - you still have the problem that the final class is conceptually supposed to be both a GenSquare and a GenPoint at the same time. If the underlying concepts behind the composed roles are fundamentally incompatable (such as a Dog and a Tree), you're going to have problems. OTOH, forcing all classes to call the role closure is bad design of the composition process. Hence I'm arguing for a super keyword that in a role refers to the class. In the example super.equal($p) calls the side checking closure. This is what happens by default; no special syntax is needed. Note that it's entirely possible for attributes to not make it into the final class, if the accessor methods get redefined in such a way as to remove reference to the attributes. This is part of the notion that roles supply an outline of what the class should do, but only the class actually supplies the definitive details of how to do it. I see that you regard the class as the ultimate definer of functionality. The role requires a method including its signature but the class implements it. For the type system the role encodes the guarantee of the method availability. Exactly. As I see it: is and does declarations in a role impose requirements on the final class: it must derive from another class (is), or it must compose another role (does). method and has are each one part requirement and one part suggestion: for method, the class is required to include a method that matches the given name (which, of course, includes the method's signature), and a particular closure is suggested that the class can accept or override. I almost agree here. The only thing I'm asking for is that the role's closure is not discarded so easily. The designer of the role takes responsibility for the role's part in the final method closure. The combination process should produce the correct result automatically and independent of the class's cooperation. Perl has yet to implement a telepathic compiler, so the compiler can only make best guesses as to what the programmer intended. For now, we have to make some concessions to reality; one such concession is that the most specific thing should have authority over (and responsibility for) the less specific things. The thing being composed into is by definition more specific than the thing being composed when it comes to implementation; thus, the latter should be given free rein to redefine the methods provided by the former - and if things go wrong, you should blame the latter rather than the former. Letting a role override a decision made by a class that it's composed into means that there's something about the role's implementation that the class cannot touch. Thus, the only things that I'd recommend using to calculate a type-boundary would be the superclasses (provided by is) and the method names (provided by method and has). That makes classes too typeish. The type system is mostly based on roles. The class inheritance graph should not be used for typing. It is a fact that class inheritance affects the behaviour of a class; it cannot be disregarded when considering type. That said, class inheritance (with respect to its semantic differences from role composition) is an area where my understanding is rather shaky. To me, the whole notion of inheritance is a bit too typeish for my tastes; I try to handle _all_ code reuse by means of roles, with classes only being brought into play when I want to be able to instantiate an object. That is, I tend to define what an object is
Re: Runtime role issues
Miroslav Silovic wrote: Paul Seamons wrote: On closer inspection, is it even possible to add a Role to a Class at runtime? If it isn't now, I would certainly like to have a hook available through MOP (which is, to the best of my knowledge, still unspecified). To modify a class at runtime, use Cis also. I thought that Class and Role composition outside of compile time resulted in a new pseudo Class for the subsequent instances of that composition - in which case the original Class would remain unmodified. I believe 'does' and 'but' operators work that way, yep. Additionally, they're per instance. Offhand I don't even recall any way to create an uninstantiated class with a role mixed at runtime (would my $class_foobar = ::Foo but ::Bar do the trick?) Probably not; but Cmy ::class_foobar := Foo but Bar might. -- Jonathan Dataweaver Lang
Re: Runtime role issues
On Thu, Oct 12, 2006 at 09:27:53AM -0700, Jonathan Lang wrote: : To modify a class at runtime, use Cis also. Cis also is compile time. You'd have to eval it. Larry
Re: Runtime role issues
Ovid wrote: The intermediate class solves the problem but it instantly suggests that we have a new design pattern we have to remember. Basically, if I can't lexically scope the additional behavior a role offers, I potentially need to remove the role or use the intermediate class pattern. my Dog $dog .= new; my $junkyard = $dog but Guard; You probably don't need to touch the class, but a particular object. You can lexically scope changes to an object using but and my quite easily. If you really need a modified class, then I think this would do it, but I'm not sure if it works: my $junkyarddog = class is Dog does Guard {}; my ::($junkyarddog) $spot .= new;
[svn:perl6-synopsis] r13096 - doc/trunk/design/syn
Author: larry Date: Thu Oct 12 14:52:22 2006 New Revision: 13096 Modified: doc/trunk/design/syn/S01.pod doc/trunk/design/syn/S05.pod Log: Changed enforced backtracking from + to ! to avoid conflicting with Friedl's ++ Modified: doc/trunk/design/syn/S01.pod == --- doc/trunk/design/syn/S01.pod(original) +++ doc/trunk/design/syn/S01.podThu Oct 12 14:52:22 2006 @@ -89,7 +89,7 @@ =item * Perl 6 should be malleable enough that it can evolve into the imaginary -perfect language, Perl 7. This darwinian imperative implies support +perfect language, Perl 7. This darwinian imperative implies support for multiple syntaxes above and multiple platforms below. =item * Modified: doc/trunk/design/syn/S05.pod == --- doc/trunk/design/syn/S05.pod(original) +++ doc/trunk/design/syn/S05.podThu Oct 12 14:52:22 2006 @@ -14,9 +14,9 @@ Maintainer: Patrick Michaud [EMAIL PROTECTED] and Larry Wall [EMAIL PROTECTED] Date: 24 Jun 2002 - Last Modified: 9 Oct 2006 + Last Modified: 12 Oct 2006 Number: 5 - Version: 38 + Version: 39 This document summarizes Apocalypse 5, which is about the new regex syntax. We now try to call them Iregex rather than regular @@ -1230,9 +1230,9 @@ never backtrack in a Ctoken unless some outer regex has specified a C:panic option that applies. If you want to prevent even that, use C*:, C+:, or C?: to prevent any backtracking into the quantifier. -If you want to explicitly backtrack, append either a C? or a C+ +If you want to explicitly backtrack, append either a C? or a C! to the quantifier. The C? forces minimal matching as usual, -while the C+ forces greedy matching. The Ctoken declarator is +while the C! forces greedy matching. The Ctoken declarator is really just short for regex :ratchet { ... } @@ -1279,16 +1279,16 @@ =item * -To force the preceding atom to do greedy backtracking, -append a C:+ or C+ to the atom. If the preceding token -is a quantifier, the C: may be omitted. (Perl 5 has no -corresponding construct because backtracking always defaults -to greedy in Perl 5.) +To force the preceding atom to do greedy backtracking in a +spot that would default otherwise, append a C:! to the atom. +If the preceding token is a quantifier, the C: may be omitted. +(Perl 5 has no corresponding construct because backtracking always +defaults to greedy in Perl 5.) =item * To force the preceding atom to do no backtracking, use a single C: -without a subsequent C? or C+. +without a subsequent C? or C!. Backtracking over a single colon causes the regex engine not to retry the preceding atom: @@ -1316,7 +1316,7 @@ an alternation, so you may also need to put C: after it if you also want to disable that. If an explicit or implicit C:ratchet has disabled backtracking by supplying an implicit C:, you need to -put an explicit C:+ after the alternation to enable backing into +put an explicit C! after the alternation to enable backing into another alternative if the first pick fails. =item *
Re: Synposis 26 - Documentation [alpha draft]
On Thu, Oct 12, 2006 at 02:55:57PM +1000, Damian Conway wrote: Dave Whipp wrote: I'm not a great fan of this concept of reservation when there is no mechanism for its enforcement (and this is perl...). What makes you assume there will be no mechanism for enforcement? The standard Pod parser (of which I have a 95% complete Perl 5 implementation) will complain bitterly--as in cyanide--when unknown pure-upper or pure-lower block names are used. That's going to cause pain when people using older parsers try to read docs written for newer ones. Would a loud warning plus some best-efforts fail-safe parsing be possible? Tim. The whole point of reserving these namespaces is not to prevent users from misusing them, but to ensure that when we eventually get around to using a particular block name, and those same users start screaming about it, we can mournfully point to the passage in the original spec and silently shake our heads. ;-) Damian
Synposis 26 - Documentation [alpha draft]
Tim Bunce wrote: Damian Conway wrote: Dave Whipp wrote: I'm not a great fan of this concept of reservation when there is no mechanism for its enforcement (and this is perl...). What makes you assume there will be no mechanism for enforcement? The standard Pod parser (of which I have a 95% complete Perl 5 implementation) will complain bitterly--as in cyanide--when unknown pure-upper or pure-lower block names are used. That's going to cause pain when people using older parsers try to read docs written for newer ones. If I understand you correctly, the pain to which you're referring would come from the possibility of a name that's reserved by the newer version of Pod, but not by the older version. Wouldn't the simplest solution be to let a Pod document announce its own version, much like Perl can? -- Jonathan Dataweaver Lang
Re: Synposis 26 - Documentation [alpha draft]
On Thu, Oct 12, 2006 at 03:57:01PM -0700, Jonathan Lang wrote: Tim Bunce wrote: Damian Conway wrote: Dave Whipp wrote: I'm not a great fan of this concept of reservation when there is no mechanism for its enforcement (and this is perl...). What makes you assume there will be no mechanism for enforcement? The standard Pod parser (of which I have a 95% complete Perl 5 implementation) will complain bitterly--as in cyanide--when unknown pure-upper or pure-lower block names are used. That's going to cause pain when people using older parsers try to read docs written for newer ones. If I understand you correctly, the pain to which you're referring would come from the possibility of a name that's reserved by the newer version of Pod, but not by the older version. Yes. Wouldn't the simplest solution be to let a Pod document announce its own version, much like Perl can? How would that actually help? The old parser still wouldn't know what new keywords have been added or how to parse them. Tim.