On Thu, Nov 10, 2005 at 10:11:50AM +0100, TSa wrote:
: HaloO,
: 
: Gaal Yahas wrote:
: >I know why the following doesn't work:
: >
: >     given $food {
: >         when Pizza | Lazagna { .eat }
: >         when .caloric_value > $doctors_orders { warn "no, no no" }
: >         # ...
: >     }
: >
: >The expression in the second when clause is smart-matched against $food,
: >not tested for truth like an if.
: 
: The smart match is hopefully *type* aware. In the above second case
: the match could be :( Item ~~ Code ) the Item is $food, the Code is the
: block { .caloric_value > $doctors_orders }. So far so bad, you say?!
: But I think the type inferencer will type the Code as :(Item --> bool)
: and as such we could specify that a booleanizing, inline block just
: does what you expect. If the same should be the case for
: 
:    sub foo:( --> bool) {...}
: 
:    given $food
:    {
:        when foo {...} # call foo and enter if true is returned
:    }
: 
: I would like that.

And, in fact, the original Apocalypse specified that behavior for
operators that were known to return boolean.  The problem is that there
are objects that *can* return boolean that you want to nevertheless
want to smartmatch against.  So you want some way to restrict it to
operations that can *only* return boolean, and only do delayed
evaluation of those.  But the phrase "delayed evaluation" says that
the "correct" workaround is:

    given $food {
        when Pizza | Lazagna { .eat }
        when { .caloric_value > $doctors_orders } { warn "no, no no" }
        # ...
    }

But if we have a mandatory type inferencer underneath that is merely
ignored when it's inconvenient, then we could probably automatically
delay evaluation of the code.  It's not much different from the
problem of

    delete %foo{$bar}

realizing that the last operation (returning the looked-up value from
the hash) has to be delayed till after the value is deleted.

In any event, you're right about the fact that it depends only on
the booleanness of the return result, not on whether the expression
"consumes" $_.  A "when true" should always execute whether or not
the topic is true or false.  We'll need to train people that

    given $boolean {
        when true {...}
        when false {...}
    }

needs to be rewritten as

    given $boolean {
        when .true {...}
        when .not {...}
    }

Fortunately, we can know something is bogus when we see the "when
false".  The question is, is it just semantically bogus or also
syntactically bogus?  The fact is that it can be syntactically bogus
two different ways.

I think this is a good argument for never importing the bool enum
<false true> into the current scope as bare names.  true() is a
predicate, not a value, so it is syntactically bogus because it
will try to eat the {...}.  "true" and "false aren't values in Perl.
The names of the values are bool::true and bool::false, but the values
of the values are 0 and 1.  And the name of the values of the values
is "bit".  (Shades of Lewis Carrol, but hey, it's before breakfast.)
So "false" is not a valid name of a value in standard Perl 6!
The actual values are just bit values.  So another way to write the
switch is:

    given $boolean {
        when 1 {...}
        when 0 {...}
    }

Of course, they'll try to outsmart us and write:

    given $boolean {
        when bool::true {...}
        when bool::false {...}
    }

which we can still recognize and carp about because the second case
creates unreachable code.

Of course, the best way to rewrite is probably just:

    if $boolean {...} else {...}

The long and the short of it is that I think we can depend on the type
inferencer here without the naïve user being aware of it, as long as
we restrict the autodelay to apply only to things that can only return
boolean officially.  We mustn't apply it to things that just happen to
be able to return boolean in boolean context, or things like

    when %foo

can't work.

Larry

Reply via email to