Iterating through two arrays at once

60 views
Skip to first unread message

Joe Gottman

unread,
Dec 10, 2003, 11:44:15 PM12/10/03
to Perl6
In Perl 6, how will it be possible to iterate through two arrays at the
same time? According to Apocalypse 4, the syntax is
for @a; @b -> $a; $b {

According to the book "Perl 6 Essentials" the syntax is
for zip(@a, @b) -> $a, $b {

Which of these is right? (of course, this being Perl, both may be right).

Whichever of these syntaxes is right, what happens when @a and @b are of
different sizes? I can think of three possible behaviors, each with its
potential drawbacks:

1) The loop executes min(+ @a, + @b) times, then finishes successfully.
2) The loop executes min(+ @a, + @b) times, then throws an exception
because the arrays were not of the same size.
3) The loop executes max(+ @a, + @b) times. If @a has fewer elements
than @b, then after @a's elements are exhausted $a is set to undef, and
similarly if @b has fewer elements than @a.

In cases 1) and 2), the problem is how to get the elements of the larger
array that were never iterated over. Case 2) is probably better than case
1), because the exception that is thrown might contain information about
which array was larger and which elements of it have yet to be examined. In
case 3), the problem is differentiating between an undef returned because
the arrays were of different sizes, and an undef returned because one of the
arrays contained an undef.

Joe Gottman

Larry Wall

unread,
Dec 11, 2003, 12:53:17 AM12/11/03
to Perl6
On Wed, Dec 10, 2003 at 11:44:15PM -0500, Joe Gottman wrote:
: In Perl 6, how will it be possible to iterate through two arrays at the

: same time? According to Apocalypse 4, the syntax is
: for @a; @b -> $a; $b {
:
: According to the book "Perl 6 Essentials" the syntax is
: for zip(@a, @b) -> $a, $b {
:
: Which of these is right? (of course, this being Perl, both may be right).

The latter is righter.

: Whichever of these syntaxes is right, what happens when @a and @b are of


: different sizes? I can think of three possible behaviors, each with its
: potential drawbacks:
:
: 1) The loop executes min(+ @a, + @b) times, then finishes successfully.
: 2) The loop executes min(+ @a, + @b) times, then throws an exception
: because the arrays were not of the same size.
: 3) The loop executes max(+ @a, + @b) times. If @a has fewer elements
: than @b, then after @a's elements are exhausted $a is set to undef, and
: similarly if @b has fewer elements than @a.

3 is what happens. That has not changed from the Apocalypse.

: In cases 1) and 2), the problem is how to get the elements of the larger


: array that were never iterated over. Case 2) is probably better than case
: 1), because the exception that is thrown might contain information about
: which array was larger and which elements of it have yet to be examined. In
: case 3), the problem is differentiating between an undef returned because
: the arrays were of different sizes, and an undef returned because one of the
: arrays contained an undef.

In Perl 6, undef is not necessarily a unique value. It might well contain an
unthrown exception with all the information you want hidden in a property.

That being said, it's generally erroneous to rely on any undefined value
regardless of its origin.

Larry

Jonathan Scott Duff

unread,
Dec 11, 2003, 12:02:16 AM12/11/03
to Joe Gottman, Perl6
On Wed, Dec 10, 2003 at 11:44:15PM -0500, Joe Gottman wrote:
> In Perl 6, how will it be possible to iterate through two arrays at the
> same time? According to Apocalypse 4, the syntax is
> for @a; @b -> $a; $b {
>
> According to the book "Perl 6 Essentials" the syntax is
> for zip(@a, @b) -> $a, $b {
>
> Which of these is right? (of course, this being Perl, both may be right).

FWIW, I like the former even though the latter has lots of precedent
in other languages.

> Whichever of these syntaxes is right, what happens when @a and @b are
> of different sizes? I can think of three possible behaviors, each with
> its potential drawbacks:
>
> 1) The loop executes min(+ @a, + @b) times, then finishes
> successfully.
> 2) The loop executes min(+ @a, + @b) times, then throws an
> exception because the arrays were not of the same size.
> 3) The loop executes max(+ @a, + @b) times. If @a has fewer
> elements than @b, then after @a's elements are exhausted $a is
> set to undef, and similarly if @b has fewer elements than @a.
>
> In cases 1) and 2), the problem is how to get the elements of the
> larger array that were never iterated over. Case 2) is probably better
> than case 1), because the exception that is thrown might contain
> information about which array was larger and which elements of it have
> yet to be examined. In case 3), the problem is differentiating between
> an undef returned because the arrays were of different sizes, and an
> undef returned because one of the arrays contained an undef.

I believe that case 3) is the "right" answer. Why do you need to
differentiate the undefs? If you cared about whether one array was
bigger than the other, surely you could check that yourself. In any
case, run-time properties (is this redundant?) can help you out.
Perhaps you get an "undef but out_of_bounds" kind of value back when
you run off the end of the shorter array.

-Scott
--
Jonathan Scott Duff
du...@lighthouse.tamucc.edu

Stéphane Payrard

unread,
Dec 11, 2003, 8:48:06 AM12/11/03
to Perl6
Hi,

I don't remember anything about enums and bitenums in the
apocalypses. This is probably not very difficult to roll out
something using macros but I feel that should belong to the
standard language.


--
stef

Larry Wall

unread,
Dec 11, 2003, 1:04:12 PM12/11/03
to Perl6, Stéphane Payrard
On Thu, Dec 11, 2003 at 02:48:06PM +0100, Stéphane Payrard wrote:
: Hi,

[Warning: speculation ahead.]

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.

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

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

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.

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

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

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.

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.

I suspect the right solution from a linguistic point of view is to make it
context sensitive but also make it easy to disambiguate.

Explicitly:

$bar.does(Color) # does $bar know how to be a Color?
$bar.as(Color) # always cast to Color

Implicitly boolean:

$bar ~~ Color # $bar.does(Color)
?$bar.Color # $bar.does(Color)
if $bar.Color # if $bar.does(Color)

Implicitly non-boolean:

+$bar.Color # +$bar.as(Color)
~$bar.Color # ~$bar.as(Color)
$($bar.Color) # $($bar.as(Color))
@($bar.Color) # @($bar.as(Color))

Then $foo.true and $foo.false work as expected. Still have to be careful
about ?$foo.boolean though.

Interestingly, we have

$foo = $bar.Color || 0xfff;

that is equivalent to

$foo = $bar.does(Color) ?? $bar.as(Color) :: 0xfff;

which means $foo could validly end up 0. Of course, // gets there by
a different route:

$foo = $bar.Color // 0xfff;

means

$foo = defined($bar.as(Color)) ?? $bar.as(Color) :: 0xfff;

I think I'm happy with that. Maybe.

Larry

Michael Lazzaro

unread,
Dec 11, 2003, 5:01:17 PM12/11/03
to Perl6

On Thursday, December 11, 2003, at 10:04 AM, Larry Wall wrote:
> Explicitly:
>
> $bar.does(Color) # does $bar know how to be a Color?
> $bar.as(Color) # always cast to Color
>
> Implicitly boolean:
>
> $bar ~~ Color # $bar.does(Color)
> ?$bar.Color # $bar.does(Color)
> if $bar.Color # if $bar.does(Color)
>
> Implicitly non-boolean:
>
> +$bar.Color # +$bar.as(Color)
> ~$bar.Color # ~$bar.as(Color)
> $($bar.Color) # $($bar.as(Color))
> @($bar.Color) # @($bar.as(Color))


So C<as> would be for casting, not coercion, right?

Suppose you have a class Foo, such that:

class Foo does (Bar, Baz) {
...
}

... or however that looks. May I then presume that

$foo.Bar.zap # ($foo.as(Bar)).zap)

calls the method C<zap> of role C<Bar>, with $foo as the invocant?


MikeL

Luke Palmer

unread,
Dec 11, 2003, 6:18:19 PM12/11/03
to Perl6, Stéphane Payrard
Larry Wall writes:
> 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

So are you saying that, eg.

class Something does Color {...}
my Something $flib;

if $flib.red { print "Flib is red" }
if $flib.true { print "Should be an error before now" }

Since Something doesn't Boolean, true would be a "method not found"
error?

If that's the case, how do we attach out-of-band properties on objects
that don't expect them, but only some of them (as was the original
intent for properties, IIRC):

my role onlyonced;
sub onlyonce($arg is rw) {
die "onlyonce called twice on the same value" if $arg.onlyonced;
$arg but= onlyonced;
}

Either that doesn't work at all, because you get an "onlyonced not
found" error, or it works because onlyonced is a declared role. But
in the latter case I worry about namespace pollution.

It's clear that I don't entirely understand all of this yet (er, as much
as there is to understand... yet).

Luke

Larry Wall

unread,
Dec 11, 2003, 7:28:28 PM12/11/03
to Perl6
On Thu, Dec 11, 2003 at 02:01:17PM -0800, Michael Lazzaro wrote:
: So C<as> would be for casting, not coercion, right?

:
: Suppose you have a class Foo, such that:
:
: class Foo does (Bar, Baz) {
: ...
: }
:
: ... or however that looks. May I then presume that
:
: $foo.Bar.zap # ($foo.as(Bar)).zap)
:
: calls the method C<zap> of role C<Bar>, with $foo as the invocant?

Seems like that would be the case.

Larry

Larry Wall

unread,
Dec 11, 2003, 8:09:45 PM12/11/03
to Perl6
On Thu, Dec 11, 2003 at 04:18:19PM -0700, Luke Palmer wrote:
: Larry Wall writes:
: > 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
:
: So are you saying that, eg.
:
: class Something does Color {...}
: my Something $flib;
:
: if $flib.red { print "Flib is red" }
: if $flib.true { print "Should be an error before now" }
:
: Since Something doesn't Boolean, true would be a "method not found"
: error?

Well, true is perhaps a bad example, since everything is boolean one
way or another. Built-in types inherit a true method that depends on the
actual value, not on a property.

: If that's the case, how do we attach out-of-band properties on objects


: that don't expect them, but only some of them (as was the original
: intent for properties, IIRC):
:
: my role onlyonced;

That might need to be "my property" to get everything defaulted for
a property kind of role. But maybe not.

: sub onlyonce($arg is rw) {


: die "onlyonce called twice on the same value" if $arg.onlyonced;
: $arg but= onlyonced;
: }
:
: Either that doesn't work at all, because you get an "onlyonced not
: found" error, or it works because onlyonced is a declared role.

I think it works because it's declared, and because you're using it
in a boolean context, so it's not really testing the value of the
property, but it's presence. The .onlyonced method merely tests
whether the object "does" onlyonced.

: But in the latter case I worry about namespace pollution.

Which namespace are you worried about polluting? It seems to me that
restricting the name to a lexical namespace and to the current object is
about as good as you can get. We're not polluting the class's namespace,
nor are we polluting the global namespace. (Though there are times where
that's the right thing to do.)

Or are you thinking that you might want to apply a property more than
once to the same object? (That would make about as much sense as
inheriting more than once directly from the same base class.)

Or are you worried that these have to be declared at all? I think we
need to declare them or we can't use them as bare identifiers. There
are no barewords in Perl 6, so they have to be something predeclared,
or otherwise syntactically distinguished. We could syntactically
distinguish them in the presence of C<but>, but that doesn't let us
use them anywhere else, and it makes C<but> into more of a macro than
an operator, which seems unclean. Letting them be bare identifiers
under the predeclared classname rule seems to be the most appropriate
way to do it, if indeed properties can be unified with roles (and
roles with classes). And I suspect they can be unified, and ought
to be unified. My goal isn't so much to make sticky notes as hard to
use as subtypes, but to make subtypes as easy to use as sticky notes.
I think it ought to be easy for any object to pretend to be some other
kind of object. Allomorphism is not just for untyped Perl scalars.

That being said, there has to be a little discipline to it, or we'll
find ourselves in property hell. I think roles provide a nice level
of discipline.

: It's clear that I don't entirely understand all of this yet (er, as much


: as there is to understand... yet).

Well, I don't entirely understand either. One thing I do understand
is that people get scared when I start thinking out loud. :-)

Larry

Uri Guttman

unread,
Dec 11, 2003, 8:18:52 PM12/11/03
to Perl6
>>>>> "LW" == Larry Wall <la...@wall.org> writes:

> Or are you worried that these have to be declared at all? I think
> we need to declare them or we can't use them as bare identifiers.
> There are no barewords in Perl 6, so they have to be something
> predeclared, or otherwise syntactically distinguished. We could
> syntactically distinguish them in the presence of C<but>, but that
> doesn't let us use them anywhere else, and it makes C<but> into more
> of a macro than an operator, which seems unclean. Letting them be
> bare identifiers under the predeclared classname rule seems to be
> the most appropriate way to do it, if indeed properties can be
> unified with roles (and roles with classes). And I suspect they can
> be unified, and ought to be unified. My goal isn't so much to make
> sticky notes as hard to use as subtypes, but to make subtypes as
> easy to use as sticky notes. I think it ought to be easy for any
> object to pretend to be some other kind of object. Allomorphism is
> not just for untyped Perl scalars.

> Well, I don't entirely understand either. One thing I do understand


> is that people get scared when I start thinking out loud. :-)

sounds like you are working on the grand unification. does string theory
have any place here? and i rarely understand your thinking until it is
set in concrete and then chopped up with a jackhammer into little itty
bitty pieces by damian. :)

uri

--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

Larry Wall

unread,
Dec 11, 2003, 8:33:27 PM12/11/03
to Perl6
On Thu, Dec 11, 2003 at 04:18:19PM -0700, Luke Palmer wrote:
: Larry Wall writes:
: > 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
:
: So are you saying that, eg.
:
: class Something does Color {...}
: my Something $flib;
:
: if $flib.red { print "Flib is red" }
: if $flib.true { print "Should be an error before now" }
:
: Since Something doesn't Boolean, true would be a "method not found"
: error?

Didn't answer your question. No, because methods that happen to be
class names are special, in this worldview.

: If that's the case, how do we attach out-of-band properties on objects


: that don't expect them, but only some of them (as was the original
: intent for properties, IIRC):
:
: my role onlyonced;
: sub onlyonce($arg is rw) {
: die "onlyonce called twice on the same value" if $arg.onlyonced;
: $arg but= onlyonced;
: }
:
: Either that doesn't work at all, because you get an "onlyonced not
: found" error, or it works because onlyonced is a declared role. But
: in the latter case I worry about namespace pollution.

Okay, maybe I understand your worry now. Are you worried that
every object implicitly has boolean methods corresponding to every
class/role/property name in scope? I can see where that might
cause some heartburn.

Larry

Jonathan Lang

unread,
Dec 11, 2003, 9:15:36 PM12/11/03
to Perl6
I'm invoking the principle that the only stupid question is the one not
asked:

Larry Wall wrote:
> if indeed properties can be unified with roles (and roles with
> classes).

Based on the source material pointed to as your inspiration for roles, I'm
a little confused as to how roles and classes could be unified. From what
I read in the source material, a key point of a role (well, they weren't
actually calling it a 'role' there, but I'm not recalling the term that
they did use) is that you get to bypass the "diamond inheritence" problem
by relegating member variables to classes, so that when you use multiple
roles to construct a class you don't have to worry about deciding which
version of the variable to access in any given method. Without that
restraint, exactly how does a role differ from a multiple inheritence
model?

---

Incidently, I think I've caught on to _one_ of the concepts in the
upcoming object-orientation proposal: linguistically, there's a triad of
"basic verbs" - namely "be", "do", and "have". If I'm following things
properly, one could think of an object's properties as things that it has,
its methods as things that it does, and its roles as things that it is.
So

my Dog $Spot has $spots;

would be a way to create an object inheriting from type Dog which has a
property called $.spots (is there a way to do @.spots?);

my Dog $Spot will rollover {...};

would be a way to create an object inheriting from type Dog which has a
method called rollover ("will" is used because "does" is essentially a
synonym for "will do", and "do" is a built-in method which often gets
called implicitly to represent the object's primary function); and

my Dog $Spot is pet;

would be a way to create an object inheriting from type Dog which has a
role called pet.

In a similar way, roles can specify things which must be included in order
for the role to be complete. Just like "is", "will", and "has" could be
thought of as ways of including roles, methods, and variables in an
object, "like", "must", and "needs" could be used respectively to specify
that the object must have the methods and variables in question added to
it to be considered complete. "like" probably needs some clarification,
in that saying that an object is "like" a role means that the object takes
all of that role's methods and variables as requirements (that is, it
requires methods with the same name and signature and properties with the
same name and type), in addition to whatever requirements said role
normally contributes.

Am I following?

=====
Jonathan "Dataweaver" Lang

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

Paul Hodges

unread,
Dec 11, 2003, 11:05:06 PM12/11/03
to Jonathan Lang, Perl6

--- Jonathan Lang <datawe...@yahoo.com> wrote:
> Incidently, I think I've caught on to _one_ of the concepts in the
> upcoming object-orientation proposal: linguistically, there's a triad
> of "basic verbs" - namely "be", "do", and "have". If I'm following
> things properly, one could think of an object's properties as things
> that it has, its methods as things that it does, and its roles as
> things that it is.

Beautiful. This has a lot of potential, although some of it is
potential to twist young minds..... It makes me want to add commas
where commas should not be.

my Dog $Spot is Pet, will { Sit() }, has @.fleas;

See what I mean? :op
But seriously, how much of that actually is valid?I doubt @.fleas will
fly (no pun intended, honest).

Chromatic

unread,
Dec 11, 2003, 11:33:10 PM12/11/03
to Jonathan Lang, Perl6
On Thu, 2003-12-11 at 18:15, Jonathan Lang wrote:

> Based on the source material pointed to as your inspiration for roles, I'm
> a little confused as to how roles and classes could be unified. From what
> I read in the source material, a key point of a role (well, they weren't
> actually calling it a 'role' there, but I'm not recalling the term that
> they did use) is that you get to bypass the "diamond inheritence" problem
> by relegating member variables to classes, so that when you use multiple
> roles to construct a class you don't have to worry about deciding which
> version of the variable to access in any given method.

That's true, but that's incidental to the point of roles. It falls out
from the important thing about roles.

> Without that restraint, exactly how does a role differ from a multiple inheritence
> model?

Roles are a *more general* means of polymorphism and code reuse than
inheritance. Inheritance is a *means* of performing a role, but it's
not the only one.

What's important about a role is that it marks the most important
question (at least for polymorphic purposes): does this thing do what
I'm about to ask it to do?

It can do that role because of inheritance, but it can also do it
because you've reimplemented all of the necessary methods, because
you've aggregated an object that perform that role, or because you're
delegating to an object that performs the role.

If the only tool in your toolbox is isa(), you must either fake up some
inheritance scheme or go without the three other allomorphic
techniques. That's a shame.

Roles exist because you can't fit all of the useful behavior in a system
into a rigid class hierarchy -- some bits apply across classes --
without creating a mess.

Again, inheritance is only one way a class can fulfill a role. It's not
the only way and it's not necessarily the best way.

See Class::Roles on the CPAN.

-- c

Jonathan Lang

unread,
Dec 12, 2003, 12:34:21 AM12/12/03
to Perl6
Paul Hodges wrote:
> Jonathan Lang <datawe...@yahoo.com> wrote:
> > Incidently, I think I've caught on to _one_ of the concepts in the
> > upcoming object-orientation proposal: linguistically, there's a triad
> > of "basic verbs" - namely "be", "do", and "have". If I'm following
> > things properly, one could think of an object's properties as things
> > that it has, its methods as things that it does, and its roles as
> > things that it is.
>
> Beautiful. This has a lot of potential, although some of it is
> potential to twist young minds..... It makes me want to add commas
> where commas should not be.
>
> my Dog $Spot is Pet, will { Sit() }, has @.fleas;
>
> See what I mean? :op

Technically, it would be "will do { Sit() }" or "does { Sit() }" or even
"does sit()"; but yes, I can see what you mean.

> But seriously, how much of that actually is valid?I doubt @.fleas will
> fly (no pun intended, honest).

I don't see why not; must every member of an aobject be a scalar? Can't
any of them be lists or hashes?


=====
Jonathan "Dataweaver" Lang

Andy Wardley

unread,
Dec 12, 2003, 4:36:45 AM12/12/03
to Larry Wall, Perl6, Stéphane Payrard
Larry Wall wrote:
> 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
> $bar.red
[...]
> $bar.red
[...]

> $baz.Byte
>
> it's asking whether the Int property fulfills the Byte constraint, but
> that's getting kind of strange.

If the roles are first class objects then their traits are defined
as methods, right?

Boolean.true($foo)
Color.red($bar)
Int.byte($baz)

Then assuming that certain objects "inherit" certain roles, you could
use something like the Perl 5 $self->SUPER::new() syntax. Only it would
look more like this:

$foo->Boolean.true
$bar->Color.red
$baz->Int.byte

> 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

[...or...]
> $baz.as(Byte)

Or:
$baz->Byte

That would make something like this:

$foo->Color.red

the same kind of thing as:

$foo.as(Color).red

A

Eirik Berg Hanssen

unread,
Dec 12, 2003, 10:05:25 AM12/12/03
to Larry Wall, Perl6
Larry Wall <la...@wall.org> writes:

> On Thu, Dec 11, 2003 at 04:18:19PM -0700, Luke Palmer wrote:
> : Larry Wall writes:
> : > Anyway, this all implies that use of a role as a method name defaults to
> : > returning whether the type in question matches the subtype.

Why? Why should it be a method? I would have though the smart
match operator would do the job better -- as well as be less painful
than the .does() method. Hey, given that it removes the ambiguities,
I would call it less painful than use of a role as a method name.


> : If that's the case, how do we attach out-of-band properties on objects
> : that don't expect them, but only some of them (as was the original
> : intent for properties, IIRC):
> :
> : my role onlyonced;
> : sub onlyonce($arg is rw) {
> : die "onlyonce called twice on the same value" if $arg.onlyonced;
> : $arg but= onlyonced;
> : }
> :
> : Either that doesn't work at all, because you get an "onlyonced not
> : found" error, or it works because onlyonced is a declared role. But
> : in the latter case I worry about namespace pollution.
>
> Okay, maybe I understand your worry now. Are you worried that
> every object implicitly has boolean methods corresponding to every
> class/role/property name in scope? I can see where that might
> cause some heartburn.

... and ditching those boolean methods might spare us those
heartburns. What do we need them for, anyway, if the smart match
operator tests for out-of-band properties?

my role onlyonced;
sub onlyonce($arg is rw) {

die "onlyonce called twice on the same value" if $arg~~onlyonced;
$arg but= onlyonced;
}

I for one would appreciate the visual clue that we access properties
and subclasses as roles ($foo~~bareword), while we access attributes
(with accessors) as methods ($foo.bareword). Different things should
look different, right?


Eirik
--
Eirik-Ber...@allverden.no
Just this .sig then
nothing more

Larry Wall

unread,
Dec 12, 2003, 11:47:06 AM12/12/03
to Perl6
On Fri, Dec 12, 2003 at 04:05:25PM +0100, Eirik Berg Hanssen wrote:
: Larry Wall <la...@wall.org> writes:
:
: > On Thu, Dec 11, 2003 at 04:18:19PM -0700, Luke Palmer wrote:
: > : Larry Wall writes:
: > : > Anyway, this all implies that use of a role as a method name defaults to
: > : > returning whether the type in question matches the subtype.
:
: Why? Why should it be a method? I would have though the smart
: match operator would do the job better -- as well as be less painful
: than the .does() method. Hey, given that it removes the ambiguities,
: I would call it less painful than use of a role as a method name.

Having slept on it overnight, I've come to the same conclusion.

: > : If that's the case, how do we attach out-of-band properties on objects


: > : that don't expect them, but only some of them (as was the original
: > : intent for properties, IIRC):
: > :
: > : my role onlyonced;
: > : sub onlyonce($arg is rw) {
: > : die "onlyonce called twice on the same value" if $arg.onlyonced;
: > : $arg but= onlyonced;
: > : }
: > :
: > : Either that doesn't work at all, because you get an "onlyonced not
: > : found" error, or it works because onlyonced is a declared role. But
: > : in the latter case I worry about namespace pollution.
: >
: > Okay, maybe I understand your worry now. Are you worried that
: > every object implicitly has boolean methods corresponding to every
: > class/role/property name in scope? I can see where that might
: > cause some heartburn.
:
: ... and ditching those boolean methods might spare us those
: heartburns. What do we need them for, anyway, if the smart match
: operator tests for out-of-band properties?

And also, smart match is the right place to put dwimmery, not method lookup.

: my role onlyonced;


: sub onlyonce($arg is rw) {
: die "onlyonce called twice on the same value" if $arg~~onlyonced;
: $arg but= onlyonced;
: }
:
: I for one would appreciate the visual clue that we access properties
: and subclasses as roles ($foo~~bareword), while we access attributes
: (with accessors) as methods ($foo.bareword). Different things should
: look different, right?

I still think that you can access the role itself as a method, but only
if it's really there. In that case the different thing is trying to be
the same. A simple property should behave like an attribute when it can.

Larry

Larry Wall

unread,
Dec 12, 2003, 1:44:05 PM12/12/03
to Perl6
On Fri, Dec 12, 2003 at 09:36:45AM +0000, Andy Wardley wrote:
: Larry Wall wrote:
: > 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
: > $bar.red
: [...]
: > $bar.red
: [...]
: > $baz.Byte
: >
: > it's asking whether the Int property fulfills the Byte constraint, but
: > that's getting kind of strange.
:
: If the roles are first class objects then their traits are defined
: as methods, right?
:
: Boolean.true($foo)
: Color.red($bar)
: Int.byte($baz)

Potentially, though roles are more properly thought of as types than classes.
That is, they're abstract sets of values. You can instantiate one sufficiently
well to take a reference to it, so that you can do

$someobject but= $somerole;

But it's not really an object in its own right, and it's not clear that
you can call any of the methods it defines unless it's part of an object.

: Then assuming that certain objects "inherit" certain roles, you could


: use something like the Perl 5 $self->SUPER::new() syntax. Only it would
: look more like this:
:
: $foo->Boolean.true
: $bar->Color.red
: $baz->Int.byte

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'm not sure how subtypes are related to types yet, syntactically speaking.
Might even be

Blackberry[green] == Color[red]

: > 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
: [...or...]
: > $baz.as(Byte)
:
: Or:
: $baz->Byte
:
: That would make something like this:
:
: $foo->Color.red
:
: the same kind of thing as:
:
: $foo.as(Color).red

I'm thinking the ordinary method

$foo.Color

implies

$foo.as(Color)

meaning that we're viewing $foo through the Color filter. If you want to
match against a value, however, you'd have to say

$foo.Color == green

or

$foo.Color ~~ green

In the latter case, you can just say

$foo ~~ green

as long as "green" is unambiguous. 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.

The interesting question to me is what

$ref = \$foo.as(Color);

returns. It looks like a typed reference to me, but it's still
a reference to the object in $foo, or can behave as one somehow.
I don't think it should generate a reference to the bare role, because
roles aren't intended to be first class objects (though you can force
them to be, I think). Roles are supposed to encapsulate abstractions
without implying objecthood. I think roles are a little bit like
quarks--they're fine in theory, but it's scary to have loose ones
floating around.

So it seems to me that $foo.Color has to return some kind of typed ref
to $foo, so that things like

$foo.Color = purple;

can work as expected. Staring at that, it seems apparent that .Color
is simply an lvalue subroutine just like any other rw attribute. An
lvalue sub can be thought of as a typed reference, I suppose. It gets
more interesting if the role has multiple attributes though. What
would

\$foo.RGB

return, I wonder, such that

$foo.RGB = ($r,$g,$b)

would work?

Larry

Austin Hastings

unread,
Dec 12, 2003, 4:13:33 PM12/12/03
to Perl6

> -----Original Message-----
> From: Larry Wall [mailto:la...@wall.org]
> 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

Austin Hastings

unread,
Dec 12, 2003, 5:24:51 PM12/12/03
to Perl6

> -----Original Message-----
> From: Larry Wall [mailto:la...@wall.org]

> Sent: Friday, December 12, 2003 1:44 PM
>


> Potentially, though roles are more properly thought of as types
> than classes.
> That is, they're abstract sets of values. You can instantiate
> one sufficiently
> well to take a reference to it, so that you can do
>
> $someobject but= $somerole;
>
> But it's not really an object in its own right, and it's not clear that
> you can call any of the methods it defines unless it's part of an object.

Presumably it will share whatever behavior Classes use to provide "static"
methods?

> : Then assuming that certain objects "inherit" certain roles, you could
> : use something like the Perl 5 $self->SUPER::new() syntax. Only it would
> : look more like this:
> :
> : $foo->Boolean.true
> : $bar->Color.red
> : $baz->Int.byte
>
> 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'm not sure how subtypes are related to types yet, syntactically
> speaking.
> Might even be
>
> Blackberry[green] == Color[red]

This syntax suggests a javascript-like similarity between classes (or
objects) and arrays. Do you want that?
Perhaps pretending hashiness would be truer to both Perl's roots and the
syntax used to construct things:

my &member_function = \Class{memberfunction};

Blackberry{green} == Color{green}

I'll suggest:

$ref = \$foo.as(Color);

be the same as:

$ref = \$foo;
$ref but= of Color; # C<of> affects type assumptions, doesn't merely add
stuff.

So that $ref is typechecked as a Color, not as a Foo.

Paul Hodges

unread,
Dec 12, 2003, 6:10:30 PM12/12/03
to Larry Wall, Perl6
Larry said:
> The interesting question to me is what
>
> $ref = \$foo.as(Color);
>
> returns. It looks like a typed reference to me, but it's still
> a reference to the object in $foo, or can behave as one somehow.
> I don't think it should generate a reference to the bare role,
> because roles aren't intended to be first class objects (though
> you can force them to be, I think). Roles are supposed to
> encapsulate abstractions without implying objecthood. I think
> roles are a little bit like quarks--they're fine in theory, but
> it's scary to have loose ones floating around.

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

And btw, just a refresher on this "assigning a ref" thing -- would the
syntax have to change at *all*?

Smylers

unread,
Dec 12, 2003, 5:11:22 PM12/12/03
to perl6-l...@perl.org
Larry Wall writes:

> I think roles are a little bit like quarks--they're fine in theory,
> but it's scary to have loose ones floating around.

Wow.

(And please can whoever looks after the quote of the day on Perl.com add
that one to the hopper ...)

Smylers

Eirik Berg Hanssen

unread,
Dec 12, 2003, 4:30:06 PM12/12/03
to Perl6
Larry Wall <la...@wall.org> writes:

When I wrote that, I still had in mind the "boolean methods
corresponding to every class/role/property name in scope" -- but I
think you mean something else when you speak of accessing the role.
Specifically, I think you mean what I would call "accessing the role's
(main) attribute". If so, we are still in agreement. If not, I am
very much confused. :-)

Red and Reddish (per your example) are not properties, given your
definition in the other thread. So you are not arguing for Red and
Reddish to be accessible as methods, I gather.

I can see this, I suppose:

$bar but= $foo.Color if $foo ~~ Color;
if $bar ~~ Reddish {
print $bar.hex_code; # hex_code is a method of the role,
# and so can be accessed directly.

$bar.Color.red = 0; # red is not a method of the role,
# and must be accessed through the
# role's main attribute (for which
# red is an lvalue method, it seems).
}

But this would all come about because the role defines an attribute
by the same name, not because method lookup scans the role namespace.
Or so I would hope.

And then it is no different from being able to access as a method
any public attribute (or other method) that the role defines -- if the
role is really there.

Or am I very much confused?


Eirik
--
Rudolph is at _least_ as real as a Cantor set or an untried recipe.
-- Joshua W. Burton <jbu...@nwu.edu>
(<6enjs1$k...@news.acns.nwu.edu>)

Larry Wall

unread,
Dec 12, 2003, 7:29:52 PM12/12/03
to Perl6
On Fri, Dec 12, 2003 at 10:30:06PM +0100, Eirik Berg Hanssen wrote:
: Larry Wall <la...@wall.org> writes:
:
: > On Fri, Dec 12, 2003 at 04:05:25PM +0100, Eirik Berg Hanssen wrote:
:
: > : I for one would appreciate the visual clue that we access properties
: > : and subclasses as roles ($foo~~bareword), while we access attributes
: > : (with accessors) as methods ($foo.bareword). Different things should
: > : look different, right?
: >
: > I still think that you can access the role itself as a method, but only
: > if it's really there. In that case the different thing is trying to be
: > the same. A simple property should behave like an attribute when it can.
:
: When I wrote that, I still had in mind the "boolean methods
: corresponding to every class/role/property name in scope" -- but I
: think you mean something else when you speak of accessing the role.
: Specifically, I think you mean what I would call "accessing the role's
: (main) attribute". If so, we are still in agreement. If not, I am
: very much confused. :-)
:
: Red and Reddish (per your example) are not properties, given your
: definition in the other thread. So you are not arguing for Red and
: Reddish to be accessible as methods, I gather.

Not any more.

: I can see this, I suppose:


:
: $bar but= $foo.Color if $foo ~~ Color;
: if $bar ~~ Reddish {
: print $bar.hex_code; # hex_code is a method of the role,
: # and so can be accessed directly.
:
: $bar.Color.red = 0; # red is not a method of the role,
: # and must be accessed through the
: # role's main attribute (for which
: # red is an lvalue method, it seems).
: }
:
: But this would all come about because the role defines an attribute
: by the same name, not because method lookup scans the role namespace.
: Or so I would hope.

Yes.

: And then it is no different from being able to access as a method


: any public attribute (or other method) that the role defines -- if the
: role is really there.
:
: Or am I very much confused?

No, I don't think you're confused. Of course, I could be confused
about that...

Larry

Larry Wall

unread,
Dec 12, 2003, 7:38:46 PM12/12/03
to Perl6
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. It might well be better to encode that choice as
part of the dog's state rather than in the references to it. 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 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...

Larry

Andy Wardley

unread,
Dec 13, 2003, 8:42:58 AM12/13/03
to Larry Wall, Perl6
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:

<xml xmlns:color="http://example.com/xml/color.xsd">
<color:green/>
</xml>

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

Paul Hodges

unread,
Dec 13, 2003, 10:16:21 AM12/13/03
to Larry Wall, Perl6

--- Larry Wall <la...@wall.org> 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

Austin Hastings

unread,
Dec 13, 2003, 12:22:00 PM12/13/03
to Perl6

> -----Original Message-----
> From: Larry Wall [mailto:la...@wall.org]

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.


Austin Hastings

unread,
Dec 13, 2003, 1:11:44 PM12/13/03
to Perl6 Language

> -----Original Message-----
> From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]
> Sent: Saturday, December 13, 2003 9:30 AM
> To: Andy Wardley; Larry Wall; Perl6; perl6-doc...@perl.org
> 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:
> >
> > <xml xmlns:color="http://example.com/xml/color.xsd">
> > <color:green/>
> > </xml>
> >
> > 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<where> 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.
>

Larry Wall

unread,
Dec 13, 2003, 3:12:59 PM12/13/03
to Perl6, Andy Wardley
On Sat, Dec 13, 2003 at 01:42:58PM +0000, 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:


:
: <xml xmlns:color="http://example.com/xml/color.xsd">
: <color:green/>
: </xml>
:
: 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

Larry Wall

unread,
Dec 13, 2003, 3:22:46 PM12/13/03
to Perl6
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

Larry Wall

unread,
Dec 13, 2003, 4:01:02 PM12/13/03
to Perl6
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

Stéphane Payrard

unread,
Dec 13, 2003, 5:04:57 PM12/13/03
to Perl6
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 *@$ref

which in turn should behave like

print @$ref

because C<print> splats its operands.

I don't pretend that C<print *$ref> is very readable, I just ask
what it does or if it is at all permitted.

--
stef

Paul Hodges

unread,
Dec 13, 2003, 6:43:00 PM12/13/03
to Larry Wall, Perl6

--- Larry Wall <la...@wall.org> 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. :-)

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

Larry Wall

unread,
Dec 13, 2003, 11:41:27 PM12/13/03
to Perl6
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

Larry Wall

unread,
Dec 14, 2003, 1:34:56 AM12/14/03
to Perl6, Stéphane Payrard
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 = (\@array, 1, 2, 3);
push *@args;

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<print> 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 *@$ref
:
: which in turn should behave like
:
: print @$ref
:
: because C<print> splats its operands.
:
: I don't pretend that C<print *$ref> 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

Reply all
Reply to author
Forward
0 new messages