Roles and Mix-ins?

2003-12-13 Thread Chris Shawmail (E-mail)
I'm still digesting the vocabulary thread, but while I do, let me ask a
question that's probably crystal clear to everyone else.

Do roles act as a form of mix-in, as Ruby modules may, and Objective-C
protocols do?

Would the following two snippets be at all equivalent?

# Perl6
role Talk {
   method say_hello {
  print "Hello world!\n"
   }
}

class Foo does Talk { ... }

Foo.new.say_hello;

# Ruby
module Talk
   def say_hello
  puts "Hello world!"
   end
end

class Foo
   include Talk
end

Foo.new.say_hello

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.545 / Virus Database: 339 - Release Date: 11/27/2003




Re: Roles and Mix-ins?

2003-12-13 Thread Luke Palmer
Chris Shawmail (E-mail) writes:
> I'm still digesting the vocabulary thread, but while I do, let me ask a
> question that's probably crystal clear to everyone else.
> 
> Do roles act as a form of mix-in, as Ruby modules may, and Objective-C
> protocols do?
> 
> Would the following two snippets be at all equivalent?

Probably, depending on what's in the eventual definition of Foo.

Roles are quite similar to mixins (as the Traits paper said that they
were inspired by mixins), but they're distinctly not the same. 

For one, one role's methods don't silently override another's.  Instead,
you get, er, role conflict and you have to disambiguate yourself.  For
two, you can attach new roles to an object at runtime (I don't know if
you can do this with mixins, actually).

> # Perl6
> role Talk {
>method say_hello {
>   print "Hello world!\n"
>}
> }
> 
> class Foo does Talk { ... }
> 
> Foo.new.say_hello;
> 
> # Ruby
> module Talk
>def say_hello
>   puts "Hello world!"
>end
> end
> 
> class Foo
>include Talk
> end
> 
> Foo.new.say_hello

Luke



Re: enums and bitenums

2003-12-13 Thread Andy Wardley
Larry Wall wrote:
> Well, we can't use -> because we're using that for something else.
> But it's certainly true that we'll have to have some mechanism for
> disambiguating Color.green from Blackberry.green.  After all,
> 
> Blackberry.green == Color.red
> 
> Or maybe it's
> 
> Blackberry::green == Color::red

[...]

> I don't know the syntax for
> disambiguating on the green end yet.  Maybe one of
> 
> $foo ~~ Color::green
> $foo ~~ Color.green
> $foo ~~ Color[green]
> 
> Or maybe something else.

How about a single colon?

 Color:green 

This is the same syntax employed in XML namespaces and URIs, for example:

http://example.com/xml/color.xsd";>
  


Don't tell me, we can't use : because we're using that for something
else.  :-)

Presumably, the parser could be smart enough to entuit the 
role on either side of a comparison if the other is specified.

   $foo:Color ~~ Color:green

   $foo ~~ Color:green  # assumes $foo:Color

   $foo:Color ~~ green  # assumes Color:green

> I'm thinking the ordinary method
> 
> $foo.Color
> 
> implies
> 
> $foo.as(Color)

What if your $foo object has a regular method called Color?  Would it 
get called in preference?

A



Re: enums and bitenums

2003-12-13 Thread Luke Palmer
Andy Wardley writes:
> Larry Wall wrote:
> > Well, we can't use -> because we're using that for something else.
> > But it's certainly true that we'll have to have some mechanism for
> > disambiguating Color.green from Blackberry.green.  After all,
> > 
> > Blackberry.green == Color.red
> > 
> > Or maybe it's
> > 
> > Blackberry::green == Color::red
> 
> [...]
> 
> > I don't know the syntax for
> > disambiguating on the green end yet.  Maybe one of
> > 
> > $foo ~~ Color::green
> > $foo ~~ Color.green
> > $foo ~~ Color[green]
> > 
> > Or maybe something else.
> 
> How about a single colon?
> 
>  Color:green 
>
> This is the same syntax employed in XML namespaces and URIs, for example:
> 
> http://example.com/xml/color.xsd";>
>   
> 
> 
> Don't tell me, we can't use : because we're using that for something
> else.  :-)

Well, yes.  It's used in the operator position already for the indirect
object syntax, so I don't think that'll fly.

Keeping with the color example, let's think about what this is doing:

$foo ~~ green

That ought to work even if you set "green" by saying:

$foo.Color = (0,1,0);

So it seems more that "green" is doubling as a predicate and a value.
Indeed, you could think of setting something to green as setting it to
"pure green" (0,1,0), but testing "green" as anything that looks
greenish -> $r,$g,$b { $g > $r + $b }.

Maybe it's a subtype[1] of the property with a default value?

That gets me thinking about how to declare that.  If a subtype is like a
parameter to the class that the class didn't really declare, I could
imagine a syntax like this:

constraint Color[green] { $.g > $.r + $.b }

That makes me woosy, though.  Maybe digging up the adverbial modifier
C should stir some ideas.

constraint green is Color { $.g > $.r + $.b }

my Color where green $spinach;

Maybe we'd better leave that one buried.

For some reason, subtypes don't feel like roles to me.  They're not so
much behaviors are they are constraints... on behavior.  Like the
opposite of roles, actually. 

Oh, we were talking about enums, right?  Um.  Yeah. 

Luke

[1] There's a term to add to the vocab sheet.  AFAIK, a subtype is a
variation on a normal type that has some constraint applied to it.
Think vague.


Re: enums and bitenums

2003-12-13 Thread Paul Hodges

--- Larry Wall <[EMAIL PROTECTED]> wrote:
> On Fri, Dec 12, 2003 at 03:10:30PM -0800, Paul Hodges wrote:
> : Ok, wait a sec. Does that mean different references to the same
> : critter can have differing sets of aspects?
> : 
> : my Dog $Spot;
> : my $doggie = Dog.new();
> : my $meandog  = \$doggie.as(AttackDog);
> : my $nicedog  = \$doggie.as(LapDog);

Forgive me, I'm trying to get accustomed to the new syntax, so let me
rewrite

> : if $me.away {
> : if $visitor.nephew {
> :$Spot = $nicedog; 
> : } else {
> :$Spot = $meandog; 
> : }
> : }

as

  $Spot = $visitor.nephew ?? $nicedog :: $meandog;

Which brings up a small side note: that's a successfully applied
boolean context for $visitor.nephew, right?

> : Now, if I'm away and someone show up, I presume that if it's my
> : nephew then $Spot.seeVisitor() will invoke the LapDog role's .wag()
> : method, but otherwise I expect it to invoke the AttackDog role's
> : .Bark() method. I realize there are other ways to get here
> : but would this *work*???
> 
> We might be able to make it work, though as you say, there are other
> ways to get there, and the chances are that at least one of them will
> be a better way.

lol -- yeah. This is the kind of code I find six months after writing
it and wonder what sort of delerium I was suffering that day. 

So what exactly does it mean to have a "typed reference"? $meandog
still a Dog, just using an AttackDog role, right? So it's type is
Dog&AttackDog? Inheritance thinking starts crowding in here and
blurring my understanding of what's going on.

> Certainly when the Dog object's class is composed, it
> will have to do something about the conflicting .seeVisitor methods
> in the two roles. 

Ah! The class has to reconcile the roles used to build it.
That would cause the same conflict between AttackDog.Bark() and
LapDog.Bark(), if each had one, but that certainly falls back to a
matter of design, and that there are better ways to build it.

I wish I had generated a better example, but for the sake of
consistency, I'll work with what we've already got, so how about
predefining defaults to resolve known conflicts?

   class Dog does LapDog {...};
   Dog.bark is default(LapDog); # I lowercased .bark() here
   class Dog does AttackDog;

   my Dog $Spot = Dog.new();
   $Spot.bark(); # yip, yip
   $Spot.AttackDog.bark();   # sick 'em!

I just noticed I had uppercased my method(s), and it was annoying me.
Anyway, that syntax looks really freaky to me. I can look at it and
know what it was *meant* to do, but how would it be implemented?
  
  Dog.bark but= LapDog;

didn't look any better, though. :(
Obviously I'm not awake yet, but maybe these rambles will be useful to
somebody?

> It might well be better to encode that choice as
> part of the dog's state rather than in the references to it. 

I'd say that was almost guaranteed to be the better way to go in
practice. I've just seen too many cases where I was handed poorly
designed legacy code and expected to hack it into some new
functionality, "oh and we need that by three today?" 

My workplace considers refactoring to be reinventing the wheel. Just
add another motor and axle over here!! sheesh, lol

> On the other hand, it might just fall out of our implementation
> that it does the right thing with typed references, if the method
> dispatch to the conflicting methods in the Dog class can have access
> to the reference types to break ties.

And since the type of the ref could be Dog&LapDog&AttackDog&Pet, that
should work. :)

> : And btw, just a refresher on this "assigning a ref" thing -- would
> : the syntax have to change at *all*?
> 
> Dunno.  I don't see anything obviously wrong with it, but then I
> never could see very well...

Yeah, right. :)

> Larry

Paul

__
Do you Yahoo!?
New Yahoo! Photos - easier uploading and sharing.
http://photos.yahoo.com/


RE: Vocabulary

2003-12-13 Thread Austin Hastings
> From: Larry Wall [mailto:[EMAIL PROTECTED]
>
> On Fri, Dec 12, 2003 at 04:27:59PM -0500, Austin Hastings wrote:
> : > -Original Message-
> : > From: Jonathan Scott Duff [mailto:[EMAIL PROTECTED]
> : > I think I'm getting it but I'm not sure.  Does something like this
> : > work?
> : >
> : >   my role Teach { ... }
> : >   my role Operate { ... }
> : >   my role Learn { ... }
> : >
> : >   my Person $frank;
> : >   { temp $frank_the_teacher = $frank does Teach; ... }
> : >   { temp $frank_the_doctor = $frank does Operate; ... }
> : >   { temp $frank_the_student = $frank does Learn; ... }
> : >
> : > I.e., we can use dynamic scoping to control how long an object
> : > fulfills a particular role?  Maybe it could also be written like so:
> : >
> : >   my Person $frank;
> : >   { my role Teach { ... }; $frank does Teach; ... }
> : >   { my role Operate { ... }; $frank does Operate; ... }
> : >   { my role Learn { ... } $frank does Learn; ... }
> : >
> : > so that when the role goes out of scope, the object no longer
> : > possesses the abilities of that role.
> : >
> : > I confuse myself everytime I think about this stuff.
> :
> : That's brilliant, if twisted. The object persists, but the
> behaviors expire.
> : There's a paradigm there, man. Write a book.
>
> The behavior probably doesn't expire unless you've cloned the object
> and the clone expires.  However, if a role goes out of its lexical
> scope, it can't be named, so it's effectively not usable unless you
> dig out a name for it via reflection.  But the information is still
> cached there, so the object could be smarter the next time it takes
> on the same role.

It's a role closure, in other words?

That being the case, how to you unapply a role?

  $frank does no Teach;

  $frank doesnt Teach;


> That being said, a role applied with C probably *should* be
> stripped out when it goes out of scope.  Could get messy though...

I can't think of a way to apply a role with temp (to a non-temp object). How
do you do it?

=Austin



RE: enums and bitenums

2003-12-13 Thread Austin Hastings


> -Original Message-
> From: Larry Wall [mailto:[EMAIL PROTECTED]
> Sent: Friday, December 12, 2003 7:39 PM
> To: Perl6
> Subject: Re: enums and bitenums
>
>
> On Fri, Dec 12, 2003 at 03:10:30PM -0800, Paul Hodges wrote:
> : Ok, wait a sec. Does that mean different references to the same critter
> : can have differing sets of aspects?
> :
> : my Dog $Spot;
> : my $doggie = Dog.new();
> : my $meandog  = \$doggie.as(AttackDog);
> : my $nicedog  = \$doggie.as(LapDog);
> : if $me.away {
> : if $visitor.nephew {
> :$Spot = $nicedog;
> : } else {
> :$Spot = $meandog;
> : }
> : }
> :
> : Now, if I'm away and someone show up, I presume that if it's my nephew
> : then $Spot.seeVisitor() will invoke the LapDog role's .wag() method,
> : but otherwise I expect it to invoke the AttackDog role's .Bark()
> : method. I realize there are other ways to get here but would this
> : *work*???
>
> We might be able to make it work, though as you say, there are other
> ways to get there, and the chances are that at least one of them will
> be a better way.  Certainly when the Dog object's class is composed, it
> will have to do something about the conflicting .seeVisitor methods
> in the two roles.

Hmm. What does that do for run-time behavior?

If you have to worry about (essentially) every possible role's namespace
conflicting with every other, the whole thing risks getting less useful
quickly.

> It might well be better to encode that choice as
> part of the dog's state rather than in the references to it.

Treat 'em as a stack. Last one applied dominates. But make sure there's a
way to unstack the roles when finished.

> On the
> other hand, it might just fall out of our implementation that it does
> the right thing with typed references, if the method dispatch to
> the conflicting methods in the Dog class can have access to the reference
> types to break ties.

That's cool.




RE: Vocabulary

2003-12-13 Thread Austin Hastings


> -Original Message-
> From: Larry Wall [mailto:[EMAIL PROTECTED]
> Sent: Friday, December 12, 2003 8:30 PM

> On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote:

> : Good. I like the mixin being available at either time. This
> makes properties
> : a lot more useful since I can provided "default" or "normal" values:
> :
> :   role Celebrated
> : does Date
> : does {
> :   method celebrated($d) { return $d.date; }
> :   }
> :
> :   class Birthday does Celebrated {
> : has $.date;
> :   }
> :
> :   my Birthday $d = Birthday.new('February', 29, 2004) but
> : Celebrated('March', 01, 2004);
> :
> :   print "My birthday is celebrated $d.celebrated";
>
> More generally, you can write the rest of the class knowing that the
> role is there if it's compiled in.
>
> : I presume that the linear order (compile time) or chronological order of
> : applying roles decides the order in which overlaid methods are
> : Ced/overlaid.
>
> The original Traits paper specifies that it's illegal to compose two
> methods of the same name into the class, and you have to rename one of
> them to get them both visible.  This is why the authors specifically
> rejected mixins, because they hide errors like this.

I'm not convinced these are errors. Having a role override methods makes
sense in a lot of ways.

Consider, for example, a caching or persistence implementation that
overrides the .STORE method of its victims.

It seems to me there's an argument both ways --

1. Code written in the absence of a role won't anticipate the role and
therefore won't take (unknowable) steps to disambiguate method calls. Ergo
method overloads are bad.

2. Roles may be written to deliberately supercede the methods of their
victims. Method overloads are vital.

This doesn't take into account role vs. role conflicts (which seem more
likely to be serendipitous).

Perhaps an "exact signature" rule would work? Such that if the method was an
exact replacement, then no error occurs, otherwise it becomes either an
error or a multi?

Alternatively, perhaps a role must declare its method to be multi or not,
and if not then the role's method overloads the original class's.

(Which takes us to retroactive multi-fication. Ugh.)

Or perhaps you just have to say "this method overloads".

> As for the relationship of "Trait" methods to other methods
> declarations, an explicit method declaration in the class proper
> overrides the composed methods, while composed methods override
> anything else in the inheritance hierarchy.

At compile time, right? Whereas composition (but=) overrides declaration at
run-time?

> : Which is it, by the way? Or is there MTOWTDI, such as a method
> modifier for
> : specifying polymorph behavior?
>
> The default way might well be the way specified in the Traits paper.
> However, their underlying language didn't support any kind of multi
> dispatch.  Perl 6 will be able to "multi" any set of names in the same
> namespace as long as the arguments are differentiable by type.  So it
> might be possible to insert a stub method declaration in the class
> proper that says "treat all composed methods of this name as multis".
> That presumes the methods take differing arguments, of course.
>
> :   method CONFORM is wrapped { ... call ... }
>
> That would be another way to do it, except that you might still have
> to switch on something to tell it which role method to call.
>
> : > A property is a simple kind of role that supplies a single attribute.
> : > The type of a property is identical to its role name.  Roles can have
> : > subtypes that function as enums when the subtypes are constrained to a
> : > single value.
> :
> : This seems really clunky for enums. It works okay for boolean, but even
> : doing month-names is going to suck pretty hard:
> :
> :   role Month;
> :
> :   role January   does Month[0];
> :   role February  does Month[1];
> :   role March does Month[2];
> :   role April does Month[3];
> :   role May   does Month[4];
> :   role June  does Month[5];
> :   role July  does Month[6];
> :   role Augustdoes Month[7];
> :   role September does Month[8];
> :   role October   does Month[9];
> :   role November  does Month[10];
> :   role December  does Month[11];
> :
> :   role Month does Int[January..December];
>
> That's why I suggested some syntactic sugar for it.  But I admit that
> treating each enum as a subtype is a stretch.  They could be constant
> methods, for instance.  In any event, the various enum names should
> probably be hidden in the Month role and not be exported by default.

Yeah, the concept is useful enough that it's probably worth a spoonful of
sugar. Perhaps it were better to think of a clever way of defining a batch
of named constants in a class declaration, so that enums could be full
classes if they want to be:

  class Month is Int {
method name {...};
has values [ January => 0, February, ..., December ];
  }

> : > You can use one of the

RE: enums and bitenums

2003-12-13 Thread Austin Hastings


> -Original Message-
> From: Luke Palmer [mailto:[EMAIL PROTECTED]
> Sent: Saturday, December 13, 2003 9:30 AM
> To: Andy Wardley; Larry Wall; Perl6; [EMAIL PROTECTED]
> Subject: Re: enums and bitenums
> 
> 
> Andy Wardley writes:
> > Larry Wall wrote:
> > > Well, we can't use -> because we're using that for something else.
> > > But it's certainly true that we'll have to have some mechanism for
> > > disambiguating Color.green from Blackberry.green.  After all,
> > > 
> > > Blackberry.green == Color.red
> > > 
> > > Or maybe it's
> > > 
> > > Blackberry::green == Color::red
> > 
> > [...]
> > 
> > > I don't know the syntax for
> > > disambiguating on the green end yet.  Maybe one of
> > > 
> > > $foo ~~ Color::green
> > > $foo ~~ Color.green
> > > $foo ~~ Color[green]
> > > 
> > > Or maybe something else.
> > 
> > How about a single colon?
> > 
> >  Color:green 
> >
> > This is the same syntax employed in XML namespaces and URIs, 
> for example:
> > 
> > http://example.com/xml/color.xsd";>
> >   
> > 
> > 
> > Don't tell me, we can't use : because we're using that for something
> > else.  :-)
> 
> Well, yes.  It's used in the operator position already for the indirect
> object syntax, so I don't think that'll fly.


Also, as Larry pointed out there's likely to be the need to talk about multiple values.
Color[green|red] is better in a lot of ways than Color::green|Color::red.


> Keeping with the color example, let's think about what this is doing:
> 
> $foo ~~ green
> 
> That ought to work even if you set "green" by saying:
> 
> $foo.Color = (0,1,0);
> 
> So it seems more that "green" is doubling as a predicate and a value.
> Indeed, you could think of setting something to green as setting it to
> "pure green" (0,1,0), but testing "green" as anything that looks
> greenish -> $r,$g,$b { $g > $r + $b }.
> 
> Maybe it's a subtype[1] of the property with a default value?
> 
> That gets me thinking about how to declare that.  If a subtype is like a
> parameter to the class that the class didn't really declare, I could
> imagine a syntax like this:
> 
> constraint Color[green] { $.g > $.r + $.b }
> 
> That makes me woosy, though.  Maybe digging up the adverbial modifier
> C should stir some ideas.
> 
> constraint green is Color { $.g > $.r + $.b }
> 
> my Color where green $spinach;

I don't understand where you were going with that.

> Maybe we'd better leave that one buried.


Speaking of predicate/value mixups:

  role green 
does Color[$.g > $.r + $.b]
does {
  method .VALUE { return (0,1,0); }
};

Then:

  my Color $g = green;
  
  my Color $c = (random(), random(), random());

  if $c == $g {
print "That's GREEN!";
  }
  elsif $c ~~ green {
print "Well, it's greenish";
  }


> For some reason, subtypes don't feel like roles to me.  They're not so
> much behaviors are they are constraints... on behavior.  Like the
> opposite of roles, actually. 
> 
> Oh, we were talking about enums, right?  Um.  Yeah. 
> 
> Luke
> 
> [1] There's a term to add to the vocab sheet.  AFAIK, a subtype is a
> variation on a normal type that has some constraint applied to it.
> Think vague.
> 



Re: Roles and Mix-ins?

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote:
: Chris Shawmail (E-mail) writes:
: > I'm still digesting the vocabulary thread, but while I do, let me ask a
: > question that's probably crystal clear to everyone else.
: > 
: > Do roles act as a form of mix-in, as Ruby modules may, and Objective-C
: > protocols do?
: > 
: > Would the following two snippets be at all equivalent?
: 
: Probably, depending on what's in the eventual definition of Foo.
: 
: Roles are quite similar to mixins (as the Traits paper said that they
: were inspired by mixins), but they're distinctly not the same. 
: 
: For one, one role's methods don't silently override another's.  Instead,
: you get, er, role conflict and you have to disambiguate yourself.  For
: two, you can attach new roles to an object at runtime (I don't know if
: you can do this with mixins, actually).

Yes, you can.  The mixin creates a new singleton class every time
you do it, derived from the previous class.  My current thinking is
that run-time roles work a little differently.  You get a singleton
class for the object the first time you apply a property, so that each
object's properties remain distinct.  However, subsequent properties
re-use the existing singleton class, and do the same role-conflict
checks at run time that "does" would do in the class definition
at compile time.  Furthermore, the singleton class is not really
derived from the original class, but just presents a different view
of the same class, so that, from the viewpoint of the object, every
role has the same standing, and run-time roles aren't privileged
above compile-time roles, as they would be if the singleton class
were really derived from the original class.  In a sense, the object
thinks it's recomposing the original class, but it's slightly wrong.

If you really want new roles to override old roles, it's easy enough
to throw a real derivation in there.  But the Traits paper argues,
and I'm inclined to agree with them, that this not what you want for
the default behavior.  Now the Traits paper was really only worrying
about composing classes at compile time, and we're extending it to
run-time.  That means you can get name collisions at run time when
you add a role.  I still think it's better to catch that sort of goof
earlier than later.  That means the syntax for C may evolve to
look more like the syntax for C.  Whatever that looks like...

Larry


Re: Vocabulary

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 12:07:40PM -0500, Austin Hastings wrote:
: > From: Larry Wall [mailto:[EMAIL PROTECTED]
: > The behavior probably doesn't expire unless you've cloned the object
: > and the clone expires.  However, if a role goes out of its lexical
: > scope, it can't be named, so it's effectively not usable unless you
: > dig out a name for it via reflection.  But the information is still
: > cached there, so the object could be smarter the next time it takes
: > on the same role.
: 
: It's a role closure, in other words?

Erm.  That's a fancy word, and I don't claim to know what it means
all the time.  I suspect the name of the role is closed but the role
itself isn't.  Alice: "If the name of the role is called Teach..."

: That being the case, how to you unapply a role?
: 
:   $frank does no Teach;
: 
:   $frank doesnt Teach;

$frank.role_manager(
action => "delete",
mode => "override_all_safety_mechanisms", 
name_the_role_is_called => "Teach"
);

Or something like that.  :-)

: > That being said, a role applied with C probably *should* be
: > stripped out when it goes out of scope.  Could get messy though...
: 
: I can't think of a way to apply a role with temp (to a non-temp object). How
: do you do it?

Well, we did set up a way for a method to be temporizable, so it
probably comes down to whether C is just syntactic sugar for a
method call that knows how to undo itself.

Larry


Re: enums and bitenums

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 01:42:58PM +, Andy Wardley wrote:
: How about a single colon?
: 
:  Color:green 

Vaguely possible, but the lexer would have to distinguish

Color:green
Color: green
Color :green

It may yet do that, but probably not for this reason.

: This is the same syntax employed in XML namespaces and URIs, for example:
: 
: http://example.com/xml/color.xsd";>
:   
: 
: 
: Don't tell me, we can't use : because we're using that for something
: else.  :-)

Depends on how we treat whitespace, and whether : becomes part of
the name.

: Presumably, the parser could be smart enough to entuit the 
: role on either side of a comparison if the other is specified.
: 
:$foo:Color ~~ Color:green
: 
:$foo ~~ Color:green  # assumes $foo:Color
: 
:$foo:Color ~~ green  # assumes Color:green

I want more than that.  I want

$foo ~~ green

to work, provided there's only one definition of "green" in scope.
That's why I'd like enums to have a mandatory type, so that they
can in fact act like subtypes.

: > I'm thinking the ordinary method
: > 
: > $foo.Color
: > 
: > implies
: > 
: > $foo.as(Color)
: 
: What if your $foo object has a regular method called Color?  Would it 
: get called in preference?

Following the Traits paper's rule, if the class itself defines a
method Color, that takes precedence over any Color methods from roles.
But if the class merely inherits a Color method, the role would
override the inherited method.  That being said, I don't think the
situation would arise often in practice if people follow the custom
of naming normal methods in lowercase and classes/roles in uppercase.

Or we could go the other way, and say that, presuming it's known that Color
is a class/role name at compile time, .Color is forced to mean .as(Color)
instantly.  It could be argued that this doesn't work so well with run-time
properties.  But you can't name a property unless a declaration is in
scope to begin with.

Of course, we could also just completely ignore the fact that Color is
a class name if there's a dot in front of it, and force everyone to
say as(Color) if that's what they mean.  That makes the indirect object
syntax a little less useful.  Instead of

$bar = Color $foo:

you'd have to say the completely non-English-like

$bar = as $foo: Color

which is perhaps not a great loss if it encourages people to say

$bar = $foo.as(Color)

instead.

Hmm.  Now I'm thinking about the problem of expanding references in
list context, since by default a reference doesn't.  If you say

print $ref

it doesn't do what you want, but

print $ref.as(Array)

might work a lot better, though of course

print @$ref

does the same thing.  But suppose instead of $ref we have a big long
expression returning an array reference.  Then the .as() form becomes
much more readable.  So it might well be that all the prefix context
operators have .as() counterparts:

~($x)   $x.as(Str)
?($x)   $x.as(Bit)
+($x)   $x.as(Num)
int($x) $x.as(Int)
$($x)   $x.as(Scalar)
@($x)   $x.as(Array)
%($x)   $x.as(Hash)

Though .as() would probably have to be somewhat magical to get the
compiler's context analyzer to realize the context of $x in the way
that the prefix operators do.  (And of course it would have to punt
on that analysis if you say $x.as($y) or some such.)

Larry


Re: enums and bitenums

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 12:22:00PM -0500, Austin Hastings wrote:
: > We might be able to make it work, though as you say, there are other
: > ways to get there, and the chances are that at least one of them will
: > be a better way.  Certainly when the Dog object's class is composed, it
: > will have to do something about the conflicting .seeVisitor methods
: > in the two roles.
: 
: Hmm. What does that do for run-time behavior?
: 
: If you have to worry about (essentially) every possible role's namespace
: conflicting with every other, the whole thing risks getting less useful
: quickly.

But with the standard approach it merely seems like the whole thing
is still useful when in fact your semantics are already clobbered
but you just don't know it yet.  Better to find out sooner than later.

: > It might well be better to encode that choice as
: > part of the dog's state rather than in the references to it.
: 
: Treat 'em as a stack. Last one applied dominates. But make sure there's a
: way to unstack the roles when finished.

Accidental stacks considered harmful.  We're trying to get rid of the
accidental ones while preserving the ability to have intentional ones.

Larry


Re: enums and bitenums

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 07:16:21AM -0800, Paul Hodges wrote:
:   $Spot = $visitor.nephew ?? $nicedog :: $meandog;
: 
: Which brings up a small side note: that's a successfully applied
: boolean context for $visitor.nephew, right?

Yes, but $visitor.nephew is no longer .does(nephew) in my current view.
You have to say

$Spot = $visitor ~~ nephew ?? $nicedog :: $meandog;

if nephew is to do any kind of implicit subtype matching.  You can also
be explicit with .does(), of course.

: > : Now, if I'm away and someone show up, I presume that if it's my
: > : nephew then $Spot.seeVisitor() will invoke the LapDog role's .wag()
: > : method, but otherwise I expect it to invoke the AttackDog role's
: > : .Bark() method. I realize there are other ways to get here
: > : but would this *work*???
: > 
: > We might be able to make it work, though as you say, there are other
: > ways to get there, and the chances are that at least one of them will
: > be a better way.
: 
: lol -- yeah. This is the kind of code I find six months after writing
: it and wonder what sort of delerium I was suffering that day. 
: 
: So what exactly does it mean to have a "typed reference"? $meandog
: still a Dog, just using an AttackDog role, right? So it's type is
: Dog&AttackDog? Inheritance thinking starts crowding in here and
: blurring my understanding of what's going on.

There are going to be some limits on what you can do.  We don't have
enough parallel universes to allow all uses of all junction types--in
the absence of quantum computing the combinatorics are not in our favor...

: > Certainly when the Dog object's class is composed, it
: > will have to do something about the conflicting .seeVisitor methods
: > in the two roles. 
: 
: Ah! The class has to reconcile the roles used to build it.
: That would cause the same conflict between AttackDog.Bark() and
: LapDog.Bark(), if each had one, but that certainly falls back to a
: matter of design, and that there are better ways to build it.
: 
: I wish I had generated a better example, but for the sake of
: consistency, I'll work with what we've already got, so how about
: predefining defaults to resolve known conflicts?
: 
:class Dog does LapDog {...};
:Dog.bark is default(LapDog); # I lowercased .bark() here
:class Dog does AttackDog;
: 
:my Dog $Spot = Dog.new();
:$Spot.bark(); # yip, yip
:$Spot.AttackDog.bark();   # sick 'em!
: 
: I just noticed I had uppercased my method(s), and it was annoying me.
: Anyway, that syntax looks really freaky to me. I can look at it and
: know what it was *meant* to do, but how would it be implemented?
:   
:   Dog.bark but= LapDog;
: 
: didn't look any better, though. :(
: Obviously I'm not awake yet, but maybe these rambles will be useful to
: somebody?

As a example of the problem with defaults, if nothing else.  :-)

: > It might well be better to encode that choice as
: > part of the dog's state rather than in the references to it. 
: 
: I'd say that was almost guaranteed to be the better way to go in
: practice. I've just seen too many cases where I was handed poorly
: designed legacy code and expected to hack it into some new
: functionality, "oh and we need that by three today?" 
: 
: My workplace considers refactoring to be reinventing the wheel. Just
: add another motor and axle over here!! sheesh, lol

With multis you can be refactoring while you're also adding motors
and axles.   :-)

: > On the other hand, it might just fall out of our implementation
: > that it does the right thing with typed references, if the method
: > dispatch to the conflicting methods in the Dog class can have access
: > to the reference types to break ties.
: 
: And since the type of the ref could be Dog&LapDog&AttackDog&Pet, that
: should work. :)

Touché.

Larry


Re: Vocabulary

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 12:50:50PM -0500, Austin Hastings wrote:
: > -Original Message-
: > From: Larry Wall [mailto:[EMAIL PROTECTED]
: > Sent: Friday, December 12, 2003 8:30 PM
: 
: > On Fri, Dec 12, 2003 at 05:17:37PM -0500, Austin Hastings wrote:
: > : I presume that the linear order (compile time) or chronological order of
: > : applying roles decides the order in which overlaid methods are
: > : Ced/overlaid.
: >
: > The original Traits paper specifies that it's illegal to compose two
: > methods of the same name into the class, and you have to rename one of
: > them to get them both visible.  This is why the authors specifically
: > rejected mixins, because they hide errors like this.
: 
: I'm not convinced these are errors. Having a role override methods makes
: sense in a lot of ways.

A role method certainly overrides inherited methods, so it's only
methods defined in the class itself we're talking about here.

: Consider, for example, a caching or persistence implementation that
: overrides the .STORE method of its victims.

I think the class is still the final arbiter of what its objects
are--there is no other entity that holds all the reins.  If a class
chooses to include a role, and that role violates the normal rules of
roles, the class is still responsible for that (or else you need some
babysitting code somewhere, hopefully in the metaclass).  Maybe that's
what a trait is--a renegade role.  Instead of

does Storable

maybe it's

is storable

: It seems to me there's an argument both ways --
: 
: 1. Code written in the absence of a role won't anticipate the role and
: therefore won't take (unknowable) steps to disambiguate method calls. Ergo
: method overloads are bad.
: 
: 2. Roles may be written to deliberately supercede the methods of their
: victims. Method overloads are vital.

I think the default has to be 1, with an explicit way to get 2, preferably
with the agreement of the class in question, though that's not absolutely
necessary if you believe in AOP.

: This doesn't take into account role vs. role conflicts (which seem more
: likely to be serendipitous).
: 
: Perhaps an "exact signature" rule would work? Such that if the method was an
: exact replacement, then no error occurs, otherwise it becomes either an
: error or a multi?

Er, which method?

: Alternatively, perhaps a role must declare its method to be multi or not,
: and if not then the role's method overloads the original class's.

No, I think the default needs to be such that the class's method is
expected to dispatch to the role's method.  If no such method exists
then it falls back on the normal role method dispatch.  In either case,
it would almost always be the case that you'd want multimethod dispatch
to the set of role methods of the same name.

I'm starting to think that any methods declared in roles are automatically
considered "multi" when composed, whether so declared or not.

: (Which takes us to retroactive multi-fication. Ugh.)

More like proactive multi-fication, I think.

: Or perhaps you just have to say "this method overloads".

If it's part of the role contract, it's part of the contract.  But maybe
that makes it a trait.

: > As for the relationship of "Trait" methods to other methods
: > declarations, an explicit method declaration in the class proper
: > overrides the composed methods, while composed methods override
: > anything else in the inheritance hierarchy.
: 
: At compile time, right? Whereas composition (but=) overrides declaration at
: run-time?

I don't think the rules for run-time roles should be different than the
rules for compile-time roles (because Perl doesn't make a hard-and-fast
distinction between compile time and run time).  And the arbitration
logic has to be somehow associated with the class, either explicitly
by the class's declarations, or by some babysitting code telling the
class how to behave given the new composition.

I've been talking about singleton classes to implement run-time
roles, but that's not quite right.  I think a class caches its
various compositions and either reuses an existing one or creates
a new composition depending on which set of roles has been bound to
the current object.  It might seem like you could have a combinatorial
explosion of the possible number of compositions if multiple properties
are applied at run time, but when you think about, the number of those
cached compositions has to be equal or less than the number of singleton
classes you'd get if you created a new one for every object with one
or more properties.  In general there will be many fewer compositions
than singletons.

So whenever you bind a run-time role, the class looks to see if it
already knows how to do the combination of roles this object wants,
and if so, the role binding is very fast.  Otherwise it creates the new
composition, checks for conflicts, resolves them (or doesn't), and then
binds the new composition as the object's current view of its class.

In a

splatting a reference

2003-12-13 Thread Stéphane Payrard
On Sat, Dec 13, 2003 at 12:12:59PM -0800, Larry Wall wrote:
> 
> print $ref
> 
> it doesn't do what you want, but
> 
> print $ref.as(Array)
> 
> might work a lot better, though of course
> 
> print @$ref
> 

What is supposed to do the splat operator in this context? My
understanding is that when an operator expects something and gets
a ref instead, the ref is dereferenced until the expected operand
is found. The interpretor barks otherwise.

So I expect 

  print *$ref

when $ref is ref to an array to be equivalent to

  print [EMAIL PROTECTED]

which in turn should behave like

  print @$ref

because C splats its operands.

I don't pretend that C is very readable, I just ask
what it does or if it is at all permitted.

--
  stef


Re: enums and bitenums

2003-12-13 Thread Paul Hodges

--- Larry Wall <[EMAIL PROTECTED]> wrote:
> On Sat, Dec 13, 2003 at 07:16:21AM -0800, Paul Hodges wrote:
> :   $Spot = $visitor.nephew ?? $nicedog :: $meandog;
> : 
> : Which brings up a small side note: that's a successfully applied
> : boolean context for $visitor.nephew, right?
> 
> Yes, but $visitor.nephew is no longer .does(nephew) in my current
> view. You have to say
> 
> $Spot = $visitor ~~ nephew ?? $nicedog :: $meandog;
> 
> if nephew is to do any kind of implicit subtype matching.  You can
> also be explicit with .does(), of course.

I knew that, lol -- but again, that's why I lurk here. I'm trying keep
my habits chasing the curve of whatever's being worked out.

> : So what exactly does it mean to have a "typed reference"? $meandog
> : still a Dog, just using an AttackDog role, right? So it's type is
> : Dog&AttackDog? Inheritance thinking starts crowding in here and
> : blurring my understanding of what's going on.
> 
> There are going to be some limits on what you can do.  We don't have
> enough parallel universes to allow all uses of all junction types--in
> the absence of quantum computing the combinatorics are not in our
> favor...

Amen, brutha. Accordingly, do we have an idea what it actually means to
add a type to something? I mean, I get that we could say

  print "yup" if $Spot ~~ AttackDog;

but is there still

  print ref $Spot;

and if so what does it print???

> : Obviously I'm not awake yet, but maybe these rambles will be useful
> : to somebody?
> 
> As a example of the problem with defaults, if nothing else.  :-)

lol -- hey, if I can be a bad example, at least my life has *some*
purpose. :)

> : My workplace considers refactoring to be reinventing the wheel.
> : Just add another motor and axle over here!! sheesh, lol
> 
> With multis you can be refactoring while you're also adding motors
> and axles.   :-)

oooOoohh.. Hey! I *LOVE* that! >:op



__
Do you Yahoo!?
New Yahoo! Photos - easier uploading and sharing.
http://photos.yahoo.com/


Re: enums and bitenums

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 03:43:00PM -0800, Paul Hodges wrote:
: Amen, brutha. Accordingly, do we have an idea what it actually means to
: add a type to something? I mean, I get that we could say
: 
:   print "yup" if $Spot ~~ AttackDog;
: 
: but is there still
: 
:   print ref $Spot;
: 
: and if so what does it print???

It still prints Dog.  The current composition of the Dog class for this
object is largely anonymous.  If it has a name, it's something like
%Dog::__COMPOSITION__{AttackDog & Pet}.  But every dog thinks its a Dog.

Larry


Re: splatting a reference

2003-12-13 Thread Larry Wall
On Sat, Dec 13, 2003 at 11:04:57PM +0100, Stéphane Payrard wrote:
: On Sat, Dec 13, 2003 at 12:12:59PM -0800, Larry Wall wrote:
: > 
: > print $ref
: > 
: > it doesn't do what you want, but
: > 
: > print $ref.as(Array)
: > 
: > might work a lot better, though of course
: > 
: > print @$ref
: > 
: 
: What is supposed to do the splat operator in this context?

Splat is a no-op in list context.  Its only use in an rvalue is
to introduce a list context where scalar context would normally
be inferred.  So you could say

@args = ([EMAIL PROTECTED], 1, 2, 3);
push [EMAIL PROTECTED];

even though push expects a scalar array ref as the first argument.

: My understanding is that when an operator expects something and gets
: a ref instead, the ref is dereferenced until the expected operand
: is found. The interpretor barks otherwise.

In scalar context, that's basically true.  (All ordinary scalars are
references anyway, which is why @_ is a call-by-reference array.)
In list context, however, a scalar variable provides a scalar value
by default.  It could be a scalar reference to the entire OED, but
Perl thinks it's a singular value, not a plural one, unless you tell
it otherwise somehow.

Actually, C was a bad example, because $ref might well be
expanded (in a sense) by the stringification implicit to print.
Instead, let's consider:

push @array, $ref;

That pushes a single reference into the array, because that is what
it looks like it's doing.  If you say

push @array, $a, $b;

it doesn't matter whether $a or $b are references to arrays--it still
only pushes two singular values into the array.  In this case you
would have to say

push @array, @$a, @$b;

to get the arrays flattened into the push's list argument.  (This is
just how it works in Perl 5 too.)

It would be possible to make the default the other way, and explicitly
mark where you *don't* want expansion, but I think it would be much
more error prone.  It would certainly make it more difficult to read
unfamiliar code and figure out what's going on.

: So I expect 
: 
:   print *$ref
: 
: when $ref is ref to an array to be equivalent to
: 
:   print [EMAIL PROTECTED]
: 
: which in turn should behave like
: 
:   print @$ref
: 
: because C splats its operands.
: 
: I don't pretend that C is very readable, I just ask
: what it does or if it is at all permitted.

It's permitted, but does nothing.  I admit that, to a C programmer, it
looks a bit like a deref, but this isn't C.  Perl has always derefed
arrays and hashes with @ and %, and that doesn't change in Perl 6.
All I'm saying above is that .as(Array) and .as(Hash) might have the
same result of explicitly dereferencing a singular reference to a
plural value.

Larry