> -----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