Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

placeholder attachment?

8 views
Skip to first unread message

Trey Harris

unread,
Apr 18, 2004, 3:47:36 PM4/18/04
to perl6-l...@perl.org
Can anyone explain the rules of placeholder attachment? i.e., in the
example in Perl6::Placeholder's manpage,

grep { $data{$^value} } 1..10;

C<$^value> is clearly intended to attach to the outer closure C<{
$data{$^value} }>, not the inner closure C<{$^value}>. But how does the
compiler know? What is the general rule?

It's easy to just say "don't nest placeholder-using closures," but that
doesn't seem workable in practice since every block is a closure, unless
placeholders are forbidden from all but the most trivial cases. Absurdly
trivial, it seems. How about

$sub = { if $^a { $^b = $^a } };

? Are there two C<$^a>'s, one masking the other? Or just one? If two,
then the code should fail at runtime for attempted assignment to an
undefined lvalue (because $^b isn't set) or more likely at compile-time
for a missing required parameter. If there's just one C<$^a>, wouldn't
C<$^b> get set to the topic of the C<if>, i.e. C<$^a> (or is the topic of
an C<if>'s first closure always C<true>?), leading to the expression being
equivalent to

$sub = ( if $^a { $^a = $^a } };

? Or will Perl DWIM and attach both $^a and $^b to the outer sub? If so,
how did it know to do that, and not attach it to whatever sub contains the
assignment to $sub?

I'm probably just confused here, but I'd appreciate some straightening
out, as it's relevant to something I'm working on. Apo 6 seems to be
silent on this (which perhaps indicates that I'm making this a lot harder
than it is).

Trey

Luke Palmer

unread,
Apr 19, 2004, 6:48:05 AM4/19/04
to Trey Harris, perl6-l...@perl.org
Trey Harris writes:
> Can anyone explain the rules of placeholder attachment? i.e., in the
> example in Perl6::Placeholder's manpage,
>
> grep { $data{$^value} } 1..10;
>
> C<$^value> is clearly intended to attach to the outer closure C<{
> $data{$^value} }>, not the inner closure C<{$^value}>. But how does the
> compiler know? What is the general rule?

This is a tough question, one to which I don't know the answer. I'll
do something different for a change and speculate :-)

In your first example, it does what you mean because the hash subscript
isn't a closure. Curlies are always closures, except when they're not
(to be specific, in hash subscripts and hash constructors).

> It's easy to just say "don't nest placeholder-using closures," but that
> doesn't seem workable in practice since every block is a closure, unless
> placeholders are forbidden from all but the most trivial cases. Absurdly
> trivial, it seems. How about
>
> $sub = { if $^a { $^b = $^a } };

I want this to work. It could look at C<if>'s signature and see that
the closure it is expecting wants arguments, and since it doesn't, it
knows that they belong outside. But that doesn't generalize.

I think a better solution would be to associate all placeholders with
the outermost closure that introduced a placeholder. For example:

$sub = { { $^a + $^b } };

Would bind them both to the inner one, while:

$sub = { $^a; { $^a + $^b } };

Would bind them both to the outer one. Since placeholders are meant for
small scopes, this seems a good heuristic. That second example was
obviously a hack to get it to work right. The clean way to do that
would be:

$sub = -> $a, $b { { $a + $b } };

Luke

Larry Wall

unread,
Apr 19, 2004, 11:36:32 AM4/19/04
to perl6-l...@perl.org
On Mon, Apr 19, 2004 at 04:48:05AM -0600, Luke Palmer wrote:
: Trey Harris writes:
: > Can anyone explain the rules of placeholder attachment? i.e., in the
: > example in Perl6::Placeholder's manpage,
: >
: > grep { $data{$^value} } 1..10;
: >
: > C<$^value> is clearly intended to attach to the outer closure C<{
: > $data{$^value} }>, not the inner closure C<{$^value}>. But how does the
: > compiler know? What is the general rule?
:
: This is a tough question, one to which I don't know the answer. I'll
: do something different for a change and speculate :-)

Hey, I never speculate. ;-)

: In your first example, it does what you mean because the hash subscript
: isn't a closure. Curlies are always closures, except when they're not
: (to be specific, in hash subscripts and hash constructors).

Yes, that's the basic rule. In Perl 5 the curlies are (potentially)
blocks, though the optimizer throws away the block entry and exit
when it thinks it can. In Perl 6 we'll just say that those aren't
blocks. If you really want a block inside a subscript, you can always
use do {}. (But merely putting semicolons inside a subscript turns
it into a multidimensional subscript, not a block.)

: > It's easy to just say "don't nest placeholder-using closures," but that


: > doesn't seem workable in practice since every block is a closure, unless
: > placeholders are forbidden from all but the most trivial cases. Absurdly
: > trivial, it seems. How about
: >
: > $sub = { if $^a { $^b = $^a } };
:
: I want this to work. It could look at C<if>'s signature and see that
: the closure it is expecting wants arguments, and since it doesn't, it
: knows that they belong outside. But that doesn't generalize.

I don't think I want that to work.

: I think a better solution would be to associate all placeholders with


: the outermost closure that introduced a placeholder. For example:
:
: $sub = { { $^a + $^b } };
:
: Would bind them both to the inner one, while:
:
: $sub = { $^a; { $^a + $^b } };
:
: Would bind them both to the outer one.

This is the sort of twisty thinking that some people can keep straight
and some people can't. That's why we simplified the list of rules
from the original placeholder RFC, after all.

: Since placeholders are meant for


: small scopes, this seems a good heuristic. That second example was
: obviously a hack to get it to work right. The clean way to do that
: would be:
:
: $sub = -> $a, $b { { $a + $b } };

Yup.

Larry

Trey Harris

unread,
Apr 19, 2004, 11:57:47 AM4/19/04
to Larry Wall, perl6-l...@perl.org
In a message dated Mon, 19 Apr 2004, Larry Wall writes:
> On Mon, Apr 19, 2004 at 04:48:05AM -0600, Luke Palmer wrote:
> : Trey Harris writes:
> : > Can anyone explain the rules of placeholder attachment? i.e., in the
> : > example in Perl6::Placeholder's manpage,
> : >
> : > grep { $data{$^value} } 1..10;
> [...]

> : In your first example, it does what you mean because the hash subscript
> : isn't a closure. Curlies are always closures, except when they're not
> : (to be specific, in hash subscripts and hash constructors).
>
> Yes, that's the basic rule. In Perl 5 the curlies are (potentially)
> blocks, though the optimizer throws away the block entry and exit
> when it thinks it can. In Perl 6 we'll just say that those aren't
> blocks. If you really want a block inside a subscript, you can always
> use do {}. (But merely putting semicolons inside a subscript turns
> it into a multidimensional subscript, not a block.)

Okay, thanks for setting me straight there.

> : > It's easy to just say "don't nest placeholder-using closures," but that
> : > doesn't seem workable in practice since every block is a closure, unless
> : > placeholders are forbidden from all but the most trivial cases. Absurdly
> : > trivial, it seems. How about
> : >
> : > $sub = { if $^a { $^b = $^a } };
> :
> : I want this to work. It could look at C<if>'s signature and see that
> : the closure it is expecting wants arguments, and since it doesn't, it
> : knows that they belong outside. But that doesn't generalize.
>
> I don't think I want that to work.

Alright, you're the boss. But it does make placeholders nearly useless,
does it not, by essentially limiting them to subs containing single
expressions?

> : I think a better solution would be to associate all placeholders with
> : the outermost closure that introduced a placeholder. For example:
> :
> : $sub = { { $^a + $^b } };
> :
> : Would bind them both to the inner one, while:
> :
> : $sub = { $^a; { $^a + $^b } };
> :
> : Would bind them both to the outer one.
>
> This is the sort of twisty thinking that some people can keep straight
> and some people can't. That's why we simplified the list of rules
> from the original placeholder RFC, after all.

What is the list of rules? That's why I asked, and I'm still not clear
exactly what happens in the example I gave. Saying that my example
shouldn't work only eliminates one of the possibilities, the one where it
works, while leaving all the ways it might not work open. It being
guaranteed to do what I don't mean is a step towards making what I mean be
something closer to what it does, but it would be helpful if I knew what
it does so that I can more finely adjust what I mean. :-)

Trey

Abhijit A. Mahabal

unread,
Apr 19, 2004, 12:00:33 PM4/19/04
to perl6-l...@perl.org
If we have a method that returns Dog if it returns anything at all, can we
say:

method foo returns Dog|undef {...}

In a similar vein, if the function reurns a dog or a refernce to an array
, can we use Dog|Array?

And is this legal:

given ($obj){
when Dog: ...
when Array: ...
#obviously $obj can be a ref to an array, not itself an array
}

--Abhijit

Abhijit A. Mahabal http://www.cs.indiana.edu/~amahabal/

Larry Wall

unread,
Apr 19, 2004, 12:26:34 PM4/19/04
to perl6-l...@perl.org
On Mon, Apr 19, 2004 at 11:00:33AM -0500, Abhijit A. Mahabal wrote:
: If we have a method that returns Dog if it returns anything at all, can we

: say:
:
: method foo returns Dog|undef {...}

Yes, but... You'd say that only if you wanted to allow a return
type that can be simultaneously Dog and undef, as well as either.
Remember that | is inclusive-OR, not exclusive. The default meaning of

method foo returns Dog {...}

is actually

method foo returns Dog^undef {...}

since any Object is implicitly allowed to be undef instead.

: In a similar vein, if the function reurns a dog or a refernce to an array


: , can we use Dog|Array?

Certainly. Again, you might wish to be more specific with Dog^Array,
though Dog|Array will certainly work, and is arguably more readable.

: And is this legal:


:
: given ($obj){
: when Dog: ...
: when Array: ...
: #obviously $obj can be a ref to an array, not itself an array

: }

Yes. Note that there's little distinction in Perl 6 between a ref to an
an array and the array itself. If you use an array in scalar context, you
automatically get the reference.

Larry

Dave Whipp

unread,
Apr 19, 2004, 12:42:14 PM4/19/04
to perl6-l...@perl.org
"Trey Harris" <tr...@sage.org> wrote i

> It's easy to just say "don't nest placeholder-using closures," but that
> doesn't seem workable in practice since every block is a closure, unless
> placeholders are forbidden from all but the most trivial cases. Absurdly
> trivial, it seems. How about
>
> $sub = { if $^a { $^b = $^a } };

I would like to think that not all blocks have the same context. We could
define a "placeholder" scope as being a lexical scope that sends data to a
block. Thus C<for>, C<map, C<grep> etc., all introduce lexical scopes that
are tagged as placeholder scopes; but C<if> and C<while> do not. Its a bit
like an inside-out-in-reverse C<wantarray> concept.


Dave.


Juerd

unread,
Apr 19, 2004, 1:01:34 PM4/19/04
to Abhijit A. Mahabal, perl6-l...@perl.org
Abhijit A. Mahabal skribis 2004-04-19 11:00 (-0500):

> when Dog: ...
> when Array: ...

Shouldn't that be:

when Dog { ... }
when Array { ... }

Or is there some .when that I have not yet heard of?


Juerd

Larry Wall

unread,
Apr 19, 2004, 1:09:12 PM4/19/04
to perl6-l...@perl.org
On Mon, Apr 19, 2004 at 08:57:47AM -0700, Trey Harris wrote:
: > : > It's easy to just say "don't nest placeholder-using closures," but that

: > : > doesn't seem workable in practice since every block is a closure, unless
: > : > placeholders are forbidden from all but the most trivial cases. Absurdly
: > : > trivial, it seems. How about
: > : >
: > : > $sub = { if $^a { $^b = $^a } };
: > :
: > : I want this to work. It could look at C<if>'s signature and see that
: > : the closure it is expecting wants arguments, and since it doesn't, it
: > : knows that they belong outside. But that doesn't generalize.
: >
: > I don't think I want that to work.
:
: Alright, you're the boss. But it does make placeholders nearly useless,
: does it not, by essentially limiting them to subs containing single
: expressions?

Placeholders are by nature useless in anything complex if nobody can
figure out their scope. The intent is to keep the rule simple enough
that you use placeholders for simple things, but -> $a,$b {...} for
more complex things.

Strictly speaking, they're not limited to single expressions.
You just can't put them into a subordinate closure. You could have
any number of statements in your block. But yes, the strong intent is
to discourage their use beyond simple expressions. You may think that
anything that can't be completely generalized is "nearly useless", but
natural language is full of non-generalizable but nevertheless useful
idioms. Linguists like to distinguish productive from non-productive
affixes, for instance. A new productive suffix in English is -gate,
which means "the scandal associated with..." On the other hand,
the bi- prefix is on the verge of dying in English, which is partly
why we found "bicoastal" funny when it was coined, I suspect. By contrast,
the -ant suffix meaning "person who does..." is pretty much completely
non-productive anymore. That doesn't mean we stop using words like
"attendant", however.

: > : I think a better solution would be to associate all placeholders with


: > : the outermost closure that introduced a placeholder. For example:
: > :
: > : $sub = { { $^a + $^b } };
: > :
: > : Would bind them both to the inner one, while:
: > :
: > : $sub = { $^a; { $^a + $^b } };
: > :
: > : Would bind them both to the outer one.
: >
: > This is the sort of twisty thinking that some people can keep straight
: > and some people can't. That's why we simplified the list of rules
: > from the original placeholder RFC, after all.
:
: What is the list of rules? That's why I asked, and I'm still not clear
: exactly what happens in the example I gave. Saying that my example
: shouldn't work only eliminates one of the possibilities, the one where it
: works, while leaving all the ways it might not work open. It being
: guaranteed to do what I don't mean is a step towards making what I mean be
: something closer to what it does, but it would be helpful if I knew what
: it does so that I can more finely adjust what I mean. :-)

There is no list of rules. There is only one rule: Placeholders bind
to the most closely surrounding closure.

If you want a list of rules, go see RFC 23. :-)

Larry

Abhijit A. Mahabal

unread,
Apr 19, 2004, 1:10:58 PM4/19/04
to Juerd, perl6-l...@perl.org

Guilty as charged. My Perl6 is getting rusty...

--Abhijit

Larry Wall

unread,
Apr 19, 2004, 1:11:30 PM4/19/04
to perl6-l...@perl.org
On Mon, Apr 19, 2004 at 07:01:34PM +0200, Juerd wrote:
: Abhijit A. Mahabal skribis 2004-04-19 11:00 (-0500):

: > when Dog: ...
: > when Array: ...
:
: Shouldn't that be:
:
: when Dog { ... }
: when Array { ... }

Yes, that's how it should be written.

: Or is there some .when that I have not yet heard of?

Nope. I was just reading the previous as pseudocode, so I didn't say
anything about it.

Larry

Larry Wall

unread,
Apr 19, 2004, 1:22:17 PM4/19/04
to perl6-l...@perl.org
On Mon, Apr 19, 2004 at 09:42:14AM -0700, Dave Whipp wrote:
: "Trey Harris" <tr...@sage.org> wrote i

We can certainly outlaw placeholders in scopes that already specify
the argument list externally (including when there are no arguments
for C<if> et al.). But what we're *not* going to do is complexify
the rules about which closure the placeholders try to bind to in the
first place. Useless generalization is a really good place to trim
the complexity of a language. And generalizing placeholders would be
useless, in my estimation, particularly since we introduced the ->
notation as an intermediate form specifically to take away the need
to generalize placeholders.

Larry

Abhijit A. Mahabal

unread,
Apr 22, 2004, 3:21:17 PM4/22/04
to perl6-l...@perl.org

This is actually a couple of questions:
1: can you extend roles by saying: role Set is extended {}
2: if yes, does this change variables for which you said $var does Set?
In other words, is the singleton class like a closure or a first-class
class?

What follows is just some example code in case my question is vague.

--Abhijit

role Set{
method add ($elt) { $self.{$elt} = 1 }
method remove ($elt) {...}
method intersection($other where Set) {
# can I write that as: method intersection (Set $other) ?
return $self.keys.grep { exists $other{$^a} }
}
}

class Set_class does Set {}

class Collector{
has %.coins does Set; # brand new singleton class
has Set_class %.stamps; # use existing class
}

my Collector $collector .= new;
$collector.coins.add(new Coin()); #okay
$collector.stamps.add(new Stamp()); #okay

# much later during compilation

role Set is extended{ # is this: die if any collision in any class
method difference ($other where Set) {...}
}

$collector.stamps.difference(...); # okay
$collector.coins.difference(...); # Is that legal?

# In other words, is the singleton class like a closure or like a
first-class class?

Larry Wall

unread,
Apr 23, 2004, 12:42:51 PM4/23/04
to perl6-l...@perl.org
On Thu, Apr 22, 2004 at 02:21:17PM -0500, Abhijit A. Mahabal wrote:
: This is actually a couple of questions:

: 1: can you extend roles by saying: role Set is extended {}

Perhaps. Classes and objects that have already composed the role
would have to be notified that they need to recalculate collisions
and flush any method caches, so it depends on the not-yet-written
notification system in Parrot. But roles are currently implemented
in Parrot as funny-looking classes, so it may naturally fall out of
the ability to extend any open class.

: 2: if yes, does this change variables for which you said $var does Set?


: In other words, is the singleton class like a closure or a first-class
: class?

I could argue that one both ways.

: role Set{


: method add ($elt) { $self.{$elt} = 1 }

That'd be:

method add ($self: $elt) { $self.{$elt} = 1 }

or

method add ($elt) { .{$elt} = 1 }

But you don't get $self for free.

: method remove ($elt) {...}


: method intersection($other where Set) {
: # can I write that as: method intersection (Set $other) ?

Yes.

: return $self.keys.grep { exists $other{$^a} }

grepping a hash?

: }
: }
:
: class Set_class does Set {}


:
: class Collector{
: has %.coins does Set; # brand new singleton class

Might have to be written as run-time rather than declarative:

has %.coins will build { $_ does Set }; # brand new singleton class

: has Set_class %.stamps; # use existing class
: }
:
: my Collector $collector .= new;
: $collector.coins.add(new Coin()); #okay
: $collector.stamps.add(new Stamp()); #okay
:
: # much later during compilation
:
: role Set is extended{ # is this: die if any collision in any class

I believe so.

: method difference ($other where Set) {...}
: }
:
: $collector.stamps.difference(...); # okay

(Okay if the role extension didn't die.)

: $collector.coins.difference(...); # Is that legal?

I think so.

: # In other words, is the singleton class like a closure or like a
: first-class class?

I suspect that roles composed into classes recalculate collisions and
die if necessary. But roles used as mixins simply hide other methods
of the same name, just as they would had the difference method been
in the role in the first place.

So I guess they don't behave like closures. That leaves open the
question of how to write it if you *do* want it to behave like a
closure. I don't think there is anything in the engine currently that
can take a "snapshot" of the class in the closure sense. Perhaps there
needs to be. Or maybe if you want a closure of a class you just
.clone the class.

Arguably, if you're going to add things into a role or class, you should
increment the version number, and just rely on versioning. In that case
you get closure semantics, since objects would know whether they were bound
to the old version or the new version.

Since you can get closure semantics that way, it seems like a good argument
for making role extensions work the other way.

Larry

Larry Wall

unread,
Apr 23, 2004, 12:48:19 PM4/23/04
to perl6-l...@perl.org
On Fri, Apr 23, 2004 at 09:42:51AM -0700, Larry Wall wrote:
: : return $self.keys.grep { exists $other{$^a} }
:
: grepping a hash?

Sorry--looked at that cross-eyed. Of course you can grep the keys...

Larry

Dan Sugalski

unread,
Apr 23, 2004, 1:00:55 PM4/23/04
to Abhijit A. Mahabal, perl6-l...@perl.org
At 2:21 PM -0500 4/22/04, Abhijit A. Mahabal wrote:
>This is actually a couple of questions:
>1: can you extend roles by saying: role Set is extended {}

Parrot will allow this, so if Larry says OK you're fine. It may be
rather significantly expensive, however. (Not nearly as bad as, say,
adding an attribute at runtime to a heavily instantiated class,
but...)

>2: if yes, does this change variables for which you said $var does Set?

Well, it changes the *classes* for which you said $var does Set. When
you throw a role on an object we're making an anonymous sub-class, so
altering the role alters the anonymous subclass rather than the
object in the subclass.

>In other words, is the singleton class like a closure or a first-class
>class?

I'm not sure how the above questions relate to this, but singleton
classes are real first-class classes.
--
Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

0 new messages