Re: A modest question (Damian, see last para please?)

2004-01-20 Thread Damian Conway
Austin Hastings wrote:


  role Dog {must bark();}
  role Tree {must bark();}
  class crossPerson {
 method bark() {speak_sharply;}
  }
  class Trog does Tree does Dog {
 method bark() {bark_like_a_trog;}
  }
  multi sub purchase(Dog $mansBestFriend) {...}
  multi sub purchase(Tree $shrubbery) {...}
  multi sub purchase($noisemaker must bark()) {...}
  my crossPerson $jack;
  purchase $jack;
  my Trog $spot;
  purchase $spot;
Which, if any, of the subs should be called in each case?  Or should the
compiler complain of duplicate definitions?
 
$jack is a crossPerson, which absolutely does NOT have the Dog or Trog or
Tree classes in its Cisa chain. If Dog and Tree are both inferred or
inferrable classes, then the two multi declarations (Dog and Tree
arguments) are identical.

Thus, there's probably a warning or an error about conflict of inference for
any call that's not passed an explicitly typed object.
I would say that in the above examples, the calls to Cpurchase must throw a 
run-time exception, since in both calls, all three of the variants are equally 
close to their argument lists in parameter space.

An exhaustive analysis of the variants could of course detect that the three 
signatures of the variants are all equivalent at compile-time, but I'm not 
sure Perl 6 will have (or indeed ought to have) such a robust static type 
inference mechanism on signatures. Mainly because that kind of inference 
easily becomes combinatoric in complexity as roles/classes become larger and 
as the number of parameters to each variant increases.

Damian



RE: A modest question

2004-01-09 Thread chromatic
On Thu, 2004-01-08 at 16:24, Jonathan Lang wrote:

 In this example, there's no difference between the Dog and Tree roles;
 however, this would almost certainly not be the case most of the time - at
 the very least, a class with a Dog role would have @.legs, while a class
 with the Tree role would have @.branches.  However, if all that happens
 when you specify a demand for the Dog role in a signature is that the
 object must meet Dog's demands, then both crossPerson and Trog will be
 accepted.  

I would consider that a mistake.

All that doing a role should imply is that somehow, that class
understands the syntax *and* semantics of the methods of that role. 
Introspection can't reliably reveal whether $some_object.bark accesses a
property (noun) or a method (verb).

It's true that looking for @.legs versus @.branches could get you
closer, but I'm not sure that it's been decided whether methods of a
role should blissfully ignore all of the object's state.  Besides, in a
delegation situation, there could easily be some sort of magic that
handles those attributes that the introspection mechanism might miss.

-- c



RE: A modest question (Damian, see last para please?)

2004-01-08 Thread Austin Hastings


Jonathan Lang [mailto:[EMAIL PROTECTED] wrote:
 Austin Hastings wrote:
  Indeed. I like the idea of dynamic anonymous roles -- it's more
  behavioral than anything else.
 
   sub print_it ($thingie must stringify()) {...}
 
  Definitely gets down to the lowest level quickly, which is nice. Even
  nicer is the ability to use this sort of requirement as kind of an
  advanced signature: declare exactly what you're going to do. (In other
  words, your signature may say
 
sub foo(Object $o) {...}
 
  because you want to accept anything in the hierarchy. But it's nice to
  extend it with
 
sub foo(Object $o must stringify() must isa() must typeof()) {...}

 Valid, if wordy.  Roles remain useful in that they provide a more concise
 way of handling this if you want it - if you've got a dozen routines that
 all Cmust isa() must typeof(), you might be better off defining a role
 that makes those demands, and then just use it.

Sure, I agree. But when you want to specify exactly what you're doing (sort
of like call-by-contract, I guess) you can get really detailed. When you
have a dozen common cases, define an inferred role. But if any object with
methods A, Q, and Z are going to be acceptable, why not?


  This kind of granularity does kind of imply a JavaScript-like ability to
  compose objects, too, no? (If you can compose requirements atomically,
  why not compose capabilities, too?)
 
my $photon does Particle does Wave {...} = spark();

 That's where Cbut comes in:

my $photon but does Particle does Wave {...} = spark();

 would be equivelent to something like

class _anonymous_photon does Particle does Wave {...}
my _anonymous_photon $photon = spark();

Is that ['but'] really necessary?

   Also: in the first of these two, would classof($thingie) actually have
   to have Stringify as a role, or would it be reasonable to instead say
   that classof($thingie) must meet Stringify's demands?  The latter
   would require more work on the compiler's part, but would be
   considerably more flexible.
 
  I prefer the latter. I want to be able to compose requirements on the
  way. I certainly don't want to have to rewrite the core libraries (or
  extend them all) just to mix in an interface role that they already
  satisfy.

 In principle, I agree with you; in practice, it may not be workable.

Verification should be just as easy for this as for a typed referenced
parameter. I don't see why it wouldn't be workable.

Perhaps Stringify $thingie requires that the Stringify role must
   actually be used, while something like $thingie like Stringify would
   only require that Stringify's demands be met?
 
  My thought would be that once you have an object in hand, you can do
  with it what you will. But all you get is the object.

 How would you handle the following:

role Dog {must bark();}
role Tree {must bark();}

class crossPerson {
   method bark() {speak_sharply;}
}

class Trog does Tree does Dog {
   method bark() {bark_like_a_trog;}
}

multi sub purchase(Dog $mansBestFriend) {...}
multi sub purchase(Tree $shrubbery) {...}
multi sub purchase($noisemaker must bark()) {...}

my crossPerson $jack;
purchase $jack;

my Trog $spot;
purchase $spot;

 Which, if any, of the subs should be called in each case?  Or should the
 compiler complain of duplicate definitions?

$jack is a crossPerson, which absolutely does NOT have the Dog or Trog or
Tree classes in its Cisa chain. If Dog and Tree are both inferred or
inferrable classes, then the two multi declarations (Dog and Tree
arguments) are identical.

Thus, there's probably a warning or an error about conflict of inference for
any call that's not passed an explicitly typed object.

Given the strictness of the Crole behavior, I think that the consistent
answer is to fail as soon as possible and report that the three purchase
subs are in conflict with each other.

(In the generally interesting case of what to do with the Dog/Tree
multisubs, I think the right answer is to catch this either when class Trog
is declared, or when Cpurchase $spot; is called. Comments from @Larry,
especially Damian, would be nice.)

=Austin



RE: A modest question

2004-01-08 Thread Austin Hastings
From: chromatic [mailto:[EMAIL PROTECTED]
 On Wed, 2004-01-07 at 00:43, Jonathan Lang wrote:
  Maybe as an alternative to
 
 role Stringify {must stringify();}
 sub print_it (Stringify $thingie) {print $thingie.stringify();}
 
  you might be able to say
 
 sub print_it ($thingie must stringify()) {print
 $thingie.stringify();}
 
  Hmm... there's a certain elegance to being able to specify one or two
  requirements directly in a signature.

 I'm not sure that works so well in practice.  You're explicitly asking
 for a method with a particular name when you're ought to be asking for a
 method with a particular meaning.  That is, if you said:

   method threaten ( $thingie must bark() ) { ... }

 passing in a Tree object would work, when what you really want something
 that does Doggish things, like a Dog, an Actor in a dog costume, or a
 RobotDog.

Ahh, this is the classic Damian interpretation.

Yes, passing in a Tree would satisfy the requirement. That's the intention.
If we wanted to say that the requirement was for a Dog role, we'd say that.
Instead, we're being very generic, and saying that anything with a bark()
method is valid fodder for this.

For example,

  sub bark_louder($it must bark()) {
System::Audio::set_volume(+5);
$it.bark;
System::Audio::set_volume(-5);
  }

 Promoting role names to a position of typishness allows roles to express
 the semantics and context of method names that method names alone can't
 express uniquely.

 Yikes, now I sound like Larry.

Sure, but you're missing the point. It's not methods instead of roles,
it's methods when even roles are too abstract.

=Austin



RE: A modest question

2004-01-08 Thread Jonathan Lang
Austin Hastings wrote:
 Jonathan Lang wrote:
  Austin Hastings wrote:
   This kind of granularity does kind of imply a JavaScript-like
   ability to compose objects, too, no? (If you can compose 
   requirements atomically, why not compose capabilities, too?)
  
 my $photon does Particle does Wave {...} = spark();
 
  That's where Cbut comes in:
 
 my $photon but does Particle does Wave {...} = spark();
 
  would be equivelent to something like
 
 class _anonymous_photon does Particle does Wave {...}
 my _anonymous_photon $photon = spark();
 
 Is that ['but'] really necessary?

Maybe; maybe not.  How about this:

When you apply Cdoes directly to an object, the result is that the
object's class is changed to a singleton class identical to its previous
class except that it also Cdoes the specified role.  When you apply
Cbut to an object, the result is that the object's class is changed to a
singleton class that Cis its former class and Cdoes the specified
role.  That is, you use Cbut when you want the new role's methods to
take precedence over the existing class methods, and you use Cdoes when
you want the existing class methods to take precedence over the new role's
methods.  In the case of Cdoes, you also need to be able to specify any
neccessary glue code (for conflict resolution, and/or to satisfy any
demands of the new role that otherwise wouldn't be satisfied).  

Also: in the first of these two, would classof($thingie) actually
have to have Stringify as a role, or would it be reasonable to 
instead say that classof($thingie) must meet Stringify's demands? 
The latter would require more work on the compiler's part, but 
would be considerably more flexible.  
  
   I prefer the latter. I want to be able to compose requirements on
   the way. I certainly don't want to have to rewrite the core 
   libraries (or extend them all) just to mix in an interface role that
   they already satisfy.
 
  In principle, I agree with you; in practice, it may not be workable.
 
 Verification should be just as easy for this as for a typed referenced
 parameter. I don't see why it wouldn't be workable.

It isn't neccessarily because validation would be difficult; although we
_are_ saying that validation would require you to do a point-by-point
comparison of the object's available methods to the role's available
methods rather than simply checking to see if the object's class has the
role itself[1].  Just as important as this point is the fact that
sometimes you'll actually want to validate against the literal presence or
absence of the role itself in the object's class, rather than whether or
not the class meets the role's demands - largely because roles can supply
methods as well as demanding them, and by asking for that role you're
actually saying that you want the class to use that role's semantics as
well as syntax.  

Thus my suggestion that the default be that if you ask for a particular
role in a signature, it will match any class that does that particular
role; if you ask for something _like_ that particular role, it will match
anything that meets that role's demands whether or not it actually does
the role.  So saying ($thing does Dog) would require that $thing Cdoes
Dog; saying ($thing like Dog) would require that $thing satisfy Dog's
demands.  What you're asking for would still be available; just not
through Cdoes.  

  How would you handle the following:
 
 role Dog {must bark();}
 role Tree {must bark();}
 
 class crossPerson {
method bark() {speak_sharply;}
 }
 
 class Trog does Tree does Dog {
method bark() {bark_like_a_trog;}
 }
 
 multi sub purchase(Dog $mansBestFriend) {...}
 multi sub purchase(Tree $shrubbery) {...}
 multi sub purchase($noisemaker must bark()) {...}
 
 my crossPerson $jack;
 purchase $jack;
 
 my Trog $spot;
 purchase $spot;
 
  Which, if any, of the subs should be called in each case?  Or should
  the compiler complain of duplicate definitions?
 
 $jack is a crossPerson, which absolutely does NOT have the Dog or Trog
 or Tree classes in its Cisa chain. 

Of course not; nothing will have Dog or Tree in their Cisa chain,
because Dog and Tree are roles, not classes.  

 If Dog and Tree are both inferred or inferrable classes, then the 
 two multi declarations (Dog and Tree arguments) are identical.

In this example, there's no difference between the Dog and Tree roles;
however, this would almost certainly not be the case most of the time - at
the very least, a class with a Dog role would have @.legs, while a class
with the Tree role would have @.branches.  However, if all that happens
when you specify a demand for the Dog role in a signature is that the
object must meet Dog's demands, then both crossPerson and Trog will be
accepted.  



[1] It gets even messier because what you're really after is whether or
not a specific syntax is legal for the object in question; it's entirely

Re: A modest question

2004-01-07 Thread Piers Cawley
chromatic [EMAIL PROTECTED] writes:

 On Tue, 2004-01-06 at 22:26, Austin Hastings wrote:

 So on the grand balance of utility, what are the metrics that traits are
 supposed to help improve?

 Two big ones:

   - naming collections of behavior that are too fine-grained to fit into
 classes cleanly
   - enabling finer-grained code reuse

 Consider a method that needs to print an object.  You might require a
 String:

   sub print_it ( String $thingie )
   {
   print $thingie;
   }

 Why does it have to be a String, though?  What prevents it from working
 with anything that can stringify, besides the overly restrictive
 signature?  What if you could say (the Perl 6 equivalent of): 

   sub print_it ( does Stringify $thingie )
   {
   print $thingie.stringify();
   }

 That's both more general and something more specific.  By asking for
 what you really want, you're not coding everyone else into a corner.

In this particular case I prefer the Smalltalk thing of requiring all
objects to have a Cprint_on($aStream) method and not even requiring
that C$aStream satisfy the Stream role. But that's probably a matter
of taste.

-- 
Beware the Perl 6 early morning joggers -- Allison Randal


Re: A modest question

2004-01-07 Thread Jonathan Lang
Piers Cawley wrote:
  Why does it have to be a String, though?  What prevents it from
  working with anything that can stringify, besides the overly 
  restrictive signature?  What if you could say (the Perl 6 equivalent 
  of): 
 
  sub print_it ( does Stringify $thingie )
  {
  print $thingie.stringify();
  }
 
  That's both more general and something more specific.  By asking for
  what you really want, you're not coding everyone else into a corner.
 
 In this particular case I prefer the Smalltalk thing of requiring all
 objects to have a Cprint_on($aStream) method and not even requiring
 that C$aStream satisfy the Stream role. But that's probably a matter
 of taste.

Maybe as an alternative to 

   role Stringify {must stringify();}
   sub print_it (Stringify $thingie) {print $thingie.stringify();}

you might be able to say

   sub print_it ($thingie must stringify()) {print $thingie.stringify();}

Hmm... there's a certain elegance to being able to specify one or two
requirements directly in a signature.  

Also: in the first of these two, would classof($thingie) actually have to
have Stringify as a role, or would it be reasonable to instead say that
classof($thingie) must meet Stringify's demands?  The latter would require
more work on the compiler's part, but would be considerably more flexible.
 Perhaps Stringify $thingie requires that the Stringify role must
actually be used, while something like $thingie like Stringify would
only require that Stringify's demands be met?  

=
Jonathan Dataweaver Lang

__
Do you Yahoo!?
Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes
http://hotjobs.sweepstakes.yahoo.com/signingbonus


RE: A modest question

2004-01-07 Thread Austin Hastings


From: Jonathan Lang [mailto:[EMAIL PROTECTED]
 Piers Cawley wrote:
   Why does it have to be a String, though?  What prevents it from
   working with anything that can stringify, besides the overly
   restrictive signature?  What if you could say (the Perl 6 equivalent
   of):
  
 sub print_it ( does Stringify $thingie )
 {
 print $thingie.stringify();
 }
  
   That's both more general and something more specific.  By asking for
   what you really want, you're not coding everyone else into a corner.
 
  In this particular case I prefer the Smalltalk thing of requiring all
  objects to have a Cprint_on($aStream) method and not even requiring
  that C$aStream satisfy the Stream role. But that's probably a matter
  of taste.

 Maybe as an alternative to

role Stringify {must stringify();}
sub print_it (Stringify $thingie) {print $thingie.stringify();}

 you might be able to say

sub print_it ($thingie must stringify()) {print $thingie.stringify();}

 Hmm... there's a certain elegance to being able to specify one or two
 requirements directly in a signature.

Indeed. I like the idea of dynamic anonymous roles -- it's more behavioral
than anything else.

 sub print_it ($thingie must stringify()) {...}

Definitely gets down to the lowest level quickly, which is nice. Even nicer
is the ability to use this sort of requirement as kind of an advanced
signature: declare exactly what you're going to do. (In other words, your
signature may say

  sub foo(Object $o) {...}

because you want to accept anything in the hierarchy. But it's nice to
extend it with

  sub foo(Object $o must stringify() must isa() must typeof()) {...}


This kind of granularity does kind of imply a JavaScript-like ability to
compose objects, too, no? (If you can compose requirements atomically, why
not compose capabilities, too?)

  my $photon does Particle does Wave {...} = spark();


 Also: in the first of these two, would classof($thingie) actually have to
 have Stringify as a role, or would it be reasonable to instead say that
 classof($thingie) must meet Stringify's demands?  The latter would require
 more work on the compiler's part, but would be considerably more flexible.

I prefer the latter. I want to be able to compose requirements on the way. I
certainly don't want to have to rewrite the core libraries (or extend them
all) just to mix in an interface role that they already satisfy.

  Perhaps Stringify $thingie requires that the Stringify role must
 actually be used, while something like $thingie like Stringify would
 only require that Stringify's demands be met?

My thought would be that once you have an object in hand, you can do with it
what you will. But all you get is the object. So:

(Anonymous)
  sub print_it($thingie must toString()) { print $thingie.toString(); }

(Yclept)
  role Stringable {
must toString();
  }

  sub print_it(Stringable $thingie) { print $thingie.toString(); }

Versus

(Discrete)
  role Stringify {
must toString();
method stringify() { return .toString(); }
  }

  sub print_it(Stringify $thingie) { print $thingie.stringify(); }

The former cases don't add any methods to the objects method table, so an
inferred object type is okay. The latter requires that a stringify()
method be available, so you'll have to have an object that declared itself
Cdoes Stringify at the outset.

=Austin



RE: A modest question

2004-01-07 Thread Jonathan Lang
Austin Hastings wrote:
 Jonathan Lang wrote:
  Maybe as an alternative to
 
 role Stringify {must stringify();}
 sub print_it (Stringify $thingie) {print $thingie.stringify();}
 
  you might be able to say
 
 sub print_it ($thingie must stringify()) {
print $thingie.stringify();}
 
  Hmm... there's a certain elegance to being able to specify one or two
  requirements directly in a signature.
 
 Indeed. I like the idea of dynamic anonymous roles -- it's more
 behavioral
 than anything else.
 
  sub print_it ($thingie must stringify()) {...}
 
 Definitely gets down to the lowest level quickly, which is nice. Even
 nicer is the ability to use this sort of requirement as kind of an 
 advanced signature: declare exactly what you're going to do. (In other 
 words, your signature may say
 
   sub foo(Object $o) {...}
 
 because you want to accept anything in the hierarchy. But it's nice to
 extend it with
 
   sub foo(Object $o must stringify() must isa() must typeof()) {...}

Valid, if wordy.  Roles remain useful in that they provide a more concise
way of handling this if you want it - if you've got a dozen routines that
all Cmust isa() must typeof(), you might be better off defining a role
that makes those demands, and then just use it.  

 This kind of granularity does kind of imply a JavaScript-like ability to
 compose objects, too, no? (If you can compose requirements atomically,
 why not compose capabilities, too?)
 
   my $photon does Particle does Wave {...} = spark();

That's where Cbut comes in: 

   my $photon but does Particle does Wave {...} = spark();

would be equivelent to something like

   class _anonymous_photon does Particle does Wave {...}
   my _anonymous_photon $photon = spark();

  Also: in the first of these two, would classof($thingie) actually have
  to have Stringify as a role, or would it be reasonable to instead say
  that classof($thingie) must meet Stringify's demands?  The latter 
  would require more work on the compiler's part, but would be 
  considerably more flexible.  
 
 I prefer the latter. I want to be able to compose requirements on the
 way. I certainly don't want to have to rewrite the core libraries (or 
 extend them all) just to mix in an interface role that they already 
 satisfy.

In principle, I agree with you; in practice, it may not be workable.  

   Perhaps Stringify $thingie requires that the Stringify role must
  actually be used, while something like $thingie like Stringify would
  only require that Stringify's demands be met?
 
 My thought would be that once you have an object in hand, you can do
 with it what you will. But all you get is the object.  

How would you handle the following: 

   role Dog {must bark();}
   role Tree {must bark();}

   class crossPerson {
  method bark() {speak_sharply;}
   }

   class Trog does Tree does Dog {
  method bark() {bark_like_a_trog;}
   }

   multi sub purchase(Dog $mansBestFriend) {...}
   multi sub purchase(Tree $shrubbery) {...}
   multi sub purchase($noisemaker must bark()) {...}

   my crossPerson $jack; 
   purchase $jack; 

   my Trog $spot; 
   purchase $spot; 

Which, if any, of the subs should be called in each case?  Or should the
compiler complain of duplicate definitions?  

=
Jonathan Dataweaver Lang

__
Do you Yahoo!?
Yahoo! Hotjobs: Enter the Signing Bonus Sweepstakes
http://hotjobs.sweepstakes.yahoo.com/signingbonus


Re: A modest question

2004-01-07 Thread chromatic
On Wed, 2004-01-07 at 00:43, Jonathan Lang wrote:

 Maybe as an alternative to 
 
role Stringify {must stringify();}
sub print_it (Stringify $thingie) {print $thingie.stringify();}
 
 you might be able to say
 
sub print_it ($thingie must stringify()) {print $thingie.stringify();}
 
 Hmm... there's a certain elegance to being able to specify one or two
 requirements directly in a signature.

I'm not sure that works so well in practice.  You're explicitly asking
for a method with a particular name when you're ought to be asking for a
method with a particular meaning.  That is, if you said:

method threaten ( $thingie must bark() ) { ... }

passing in a Tree object would work, when what you really want something
that does Doggish things, like a Dog, an Actor in a dog costume, or a
RobotDog.

Promoting role names to a position of typishness allows roles to express
the semantics and context of method names that method names alone can't
express uniquely.

Yikes, now I sound like Larry.

LarryOr maybe not./Larry

-- c



Re: A modest question

2004-01-06 Thread chromatic
On Tue, 2004-01-06 at 22:26, Austin Hastings wrote:

 So on the grand balance of utility, what are the metrics that traits are
 supposed to help improve?

Two big ones:

- naming collections of behavior that are too fine-grained to fit into
classes cleanly
- enabling finer-grained code reuse

Consider a method that needs to print an object.  You might require a
String:

sub print_it ( String $thingie )
{
print $thingie;
}

Why does it have to be a String, though?  What prevents it from working
with anything that can stringify, besides the overly restrictive
signature?  What if you could say (the Perl 6 equivalent of): 

sub print_it ( does Stringify $thingie )
{
print $thingie.stringify();
}

That's both more general and something more specific.  By asking for
what you really want, you're not coding everyone else into a corner.

Take Mail::SimpleList and Mail::TempAddress, for example.  Both have
classes that represent individual addresses or mailing lists.  The
appropriate parent class is Mail::Action::Address, which has the very
basic data and properties that both subclasses share.

Both simple lists and temp addresses should contain expiration dates, so
both classes need some sort of behavior to implement that.

When you throw another class into the mix, say, Mail::OneWayList, where
there's no expiration (trust me, even though it's not on the CPAN yet),
there's a problem.

I'd like to share code between all three classes that represent aliases
and Mail::Action::Address is the appropriate place to do that.  I don't
want to share *all* of the code, though, so I can't really put the
expiration code in Mail::Action::Address.

I *could* subclass Mail::Action::Address and make
Mail::Action::Address::Expires and change the parent class of the temp
address and the simple list classes, but that's kinda icky as it leads
to yet another level in the class hierarchy.

By turning expiration into a role, though, everything can extend
Mail::Action::Address and only those classes that really need expiration
can do it -- and they share the code.

Contrived example?  Maybe.  Maybe not.  Consider further James
Fitzgibbon's Mail::Action::Role::Purge.  James wanted to extend all
Mail::Action subclasses to allow purging of expired addresses or lists. 
That's reasonable, but it's not something I wanted to add to
Mail::Action because it doesn't know anything about expiration.

So he made it a role and decorates expirable objects with the role and
can do what he wants there.

Again, the goals are specificity, genericity, and improved reuse.

-- c