> -----Original Message-----
> From: Larry Wall [mailto:[EMAIL PROTECTED]
> Sent: Thursday, December 11, 2003 1:04 PM
> [Warning: speculation ahead.]
Noted.
> I've been thinking that enums might just be subtypes of roles/properties.
> After all, when you say
>
> 0 but true
>
> it might really mean
>
> 0 but Boolean[1]
>
> whereas
>
> 1 but false
>
> means
>
> 1 but Boolean[0]
>
> That is, type boolean can be thought of as enum(false,true).
>
> So we might have a role declaration somewhere that says something like:
>
> role *Boolean[Bit ?$val] does Property {
> bit $.boolean = $val;
> }
> role *false does Boolean[0];
> role *true does Boolean[1];
>
> That's what the semantics might look like, but of course people would
> probably want an enum or bitenum wrapper macro for real code. No reason
> it couldn't be a standard macro though. Or even part of the
> grammar--we've
> never shied away from defining one construct in terms of another for
> teaching purposes. We define C<use> in terms of C<BEGIN> and C<require>,
> and C<require> in terms of C<do>. Perl 6 will do more of that, because
> it makes things easy to learn.
Supertypes, eh? An enum is a limited-range thingy (int, usually), which fits
the description of a role, but also has magic words involved.
package RGB;
enum Color does Int[0..0xFF_FF_FF] {
has $Red = 0xFF_00_00;
has $Green = 0x00_FF_00;
has $Blue = 0x00_00_FF;
}
Since the possible values are "possibles", I don't like C<has> unless we
provide that C<has> means "possible value" in an enum-decl.
Is C<enum> a primitive type only?
Or can we enumerate objects? As in,
class RGB {
has byte $.red;
has byte $.green;
has byte $.blue;
}
enum Color does RGB {
has $Red = RGB[red => 0xFF, blue => 0x00, green => 0x00];
has $Green = RGB[red => 0xFF, blue => 0x00, green => 0x00]; # Squares
mean compile time (const)?
has $Blue = RGB[red => 0xFF, blue => 0x00, green => 0x00];
}
> A lot of this is negotiable, but I think it's a feature that you
> can't have an enum without it being associated with a unique type
> name/property. It's also appealing to me that enum "values" live
> in the type namespace, since they're really subtypes (that is, types
> that restrict values ranges of "real" types). There's nothing says
> a subtype has to have only one value:
>
> role Bit[Int ?$val] does Int[0|1];
>
> Of course, I'm handwaving a lot here by using a junction. For
> integer subtypes you'd typically want a range:
>
> role Byte[Int ?$val] does Int[0..255];
I don't understand the purpose of your [Int ?$val] "parameter". Doesn't the
C<does Int[0..255]> declare the constraint entirely?
role PHB does Employee[$.job_title == "manager" && $.experience > 5];
> That implies that the argument to Int[] has to be able to take a range.
> I confess I don't know what the real declaration of "Int" looks like
> yet. Certainly the first arg isn't simply an "Int". That only works
> for enums. The arg has to represent some kind of generic constraint.
> Pity the optimizer...
macro does is parsed(/ <class> [ <given_block ] /) {...}
> Anyway, this all implies that use of a role as a method name defaults to
> returning whether the type in question matches the subtype. That is,
> when you say
>
> $foo.true
>
> it's asking whether the Boolean property fulfills the true constraint.
> When you say
>
> $bar.red
>
> it's asking whether the Color property fulfills the red constraint.
> I suppose when you say
>
> $baz.Byte
>
> it's asking whether the Int property fulfills the Byte constraint, but
> that's getting kind of strange.
This is bad. Better to treat a "role" as a matchable constraint, and ask:
if $foo ~~ true {...}
given $bar { when red {...}}
unless $baz ~~ Byte {...}
We've already got a constraint matching syntax. But for cases where you want
to be explicit, or when you risk confusion using ~~, we can recycle C<does>
somehow:
if $foo.does(true)
or
if $foo.can(true)
or
if $foo.would(true)
or
role ChuckWood does WoodChuck[does &.chuck(Wood)]; # Internal C<does>
for has-method-p?
my $how_much is Quantity of Wood = $woodchuck.can_chuck if
$woodchuck.could(ChuckWood)
(Sorry)
> Another implication is that, if properties are subtypes, we can't use
> the same name as a cast method. Since
>
> $baz.Byte
>
> only returns true or false, we'd need something like (yuck)
>
> $baz.asByte
>
> Since class names are valid as bare names, perhaps we can improve
> that to
>
> $baz.as(Byte)
>
> (That doesn't mean you have to write an "as" method that contains a
> switch. More likely "as" is a multi method within the class of $baz.)
Ugh.
UghUgh.
If a role is just a constraint, then there's no need to have a method at
all -- the type doesn't change.
role FitsInByte does Int[0..255];
my Byte $b;
my Int $i;
$b = $i if $i ~~ FitsInByte;
Which leaves the .as() method for conversions:
role ClassByte does Class[Byte];
multi method Int::as(Int $i: ClassByte) returns Byte { $i % 256; }
my Byte $b = $i.as(Byte);
(BTW: Is this use of roles to select a [range of] value for a parameter,
considered okay?)
> Another possibility is that .Byte would have to be context sensitive.
> In which case we have the small problem that
>
> if $foo.boolean { print "true" } else { print "false" }
>
> prints "true" even if $foo is 0. You'd have to say
>
> if +$foo.boolean { print "true" } else { print "false" }
>
> to force a numeric context on the type. (Or use $foo.true.)
Or use C<if $foo> or C<if +$foo>.
> Alternately, we use the type name as a cast always, and distinguish
> the boolean test:
>
> if $baz.does(Byte) { my $byte = $baz.Byte }
>
> I kinda like that.
>
> Since "does" is a generalization of "isa", we probably need to generalize
> smart matching to test "does" rather than "isa" for class/type names.
Or the other way around.
But if roles can be extended to nontrivial classes, like RGB above:
role Color does [has $.red and has $.green and has $.blue];
That implies either that doing
my $pixel = $rainbow.Color;
will somehow figure out the right way to extract the red, green, and blue
components from $rainbow, and bundle them up for $pixel. That doesn't seem
hard until someone adds a constraint that references another member in
passing that SHOULDN'T be part of the conversion:
role Color does [has $.red and has $.green and has $.blue and $.gamma !=
0];
Autogeneration of conversion methods sounds cool (and the PL/I meter goes
++) but it makes me awfully nervous about the AAD/PLS (*) risks.
> On the other hand, it'd be a major pain to have to write $foo.does(true).
> I suppose a cast could return undef if it fails, which means that
> $foo.true would return 1 or undef. Except $foo.false would return 0 or
> undef. Urg.
Smartmatch.
=Austin
(*) Action At a Distance / Principle of Least Surprise