[Israel.pm] List of all contexts in Perl

Yuval Kogman nothingmuch at woobling.org
Sun May 30 12:52:50 PDT 2010


On 30 May 2010 22:18, Offer Kaye <offer.kaye at gmail.com> wrote:

> When Terminologies Collide! Movie at 10!
> I fear the word "context" is being rather heavily overloaded in this
> discussion ;)

oops, sorry!

>>     my $foo = foo();
>>     if ( $foo ) { # not boolean context
>>
>>     if ( foo() ) { # boolean context
>>
>
> Except for looking at the opcodes, how can you tell there is a
> difference in context here? Shouldn't these 2 paragraphs do exactly
> the same, from my viewpoint as a user?

Well, if 'foo()' uses Want it might behave differently. Or if it
returned an lvalue (not in this example, but my $foo = foo(); $foo =
"bar"; copies the lvalue whereas foo() = "bar" modifies the SV
returned by foo(). for (foo()) { $_ = "bar" } uses aliasing semantics
so that would actually modify the lvalue too.. etc etc.

There's a million other ways something *could* cause such code to not
behave in exactly the same way.

However, I absolutely agree that they *should* do exactly the same thing.

> If the opcodes are the same, doesn't that mean calling one of the
> options "boolean context" and the other "not boolean context" is
> wrong?

Want's boolean context is a sub type of scalar context. It defines a
hierarchy, and most of the useful info is about scalars.

In this case, boolean means scalar, plus knowlege of the fact that the
returned value is going to be used only in a way that it's evaluated
as true/false and then discarded, that is as part of a branch
(if/while or a short circuiting binary operator).

This means that if you have a method like:

sub user { $self->{user} || $self->get_user_from_storage($self->{user_token}) }

then if ( $obj->user ) might be fetching the user even though it
really only wants to check that the user token is valid.

IMO the real solution is just to provide an API for asking what you
mean to ask, instead of trickery and deceit (for example
$obj->user_is_valid might validate the a cookie but won't necessarily
query the database).

> If the opcodes are different but the end result the same, this seems
> like a nice place for optimization (by letting the more
> memory/cpu-intensive/longer-runtime option collapse to the first), no?
> :)

in theory yes, but that's a tricky optimization in practice.

It's not so tricky in languages that have static typing, but perl is
very effect oriented, and this stuff *is* meaningful (some observable
differences: the used value is copied in the first variant, but not in
the second, the lexical $foo could be captured in a closure, and that
closure could be unknown at the time of compilation (e.g. eval 'sub {
$foo }') and therefore is available at runtime, etc etc etc...

For those other languages this sort of optimization typically requires
SSA form for the program, which is really hard to devise for Perl
without placing some restrictions on what you're expected to be
allowed to do.

I actually blogged about this way back:
http://blog.woobling.org/2009/11/restricted-perl.html

Theoretically under a restricted Perl you'd be making a promise that
those two things are truly identical, and therefore the compiler could
be allowed to do what it wants.

Unfortunately with the current status quo only the human is allowed to
decide whether or not something is really what it appears to be,
because the user can both realize they made a mistake and afford to go
back and try again...

If Perl had static bindings (all assignments behaved like Data::Alias
semantics by default) then '$foo' would be just a symbol, not a
container, and this optimization would have been more realistic to
perform (if you also checked to see there was no other potential user
of '$foo', like string eval or something. but this would still break
PadWalker).


More information about the Perl mailing list