Don't understand: when('foo' and/or 'bar')

W

Wolfram Humann

Would someone be so kind to explain the following (quotes are for
win32 perl):

perl -E" $u='foo'; given($u){ when('foo' and 'bar'){say 'f'}
default{say 'd'} } "
d
perl -E" $u='bar'; given($u){ when('foo' and 'bar'){say 'f'}
default{say 'd'} } "
f
perl -E" $u='baz'; given($u){ when('foo' and 'bar'){say 'f'}
default{say 'd'} } "
d
perl -E" $u='foo'; given($u){ when('foo' or 'bar'){say 'f'}
default{say 'd'} } "
f
perl -E" $u='bar'; given($u){ when('foo' or 'bar'){say 'f'}
default{say 'd'} } "
d
perl -E" $u='baz'; given($u){ when('foo' or 'bar'){say 'f'}
default{say 'd'} } "
d

My expectation was: smart matching of two strings uses 'eq'. $u can
not be equal to both 'foo' and 'bar' at the same time so in the 'and'
case I always expect the default 'd'. In the 'or' case I expect 'f' to
be printed if $u is either 'foo' or 'bar'.
Why is my expectation wrong?
 
W

Willem

Wolfram Humann wrote:
) Would someone be so kind to explain the following (quotes are for
) win32 perl):
)
) perl -E" $u='foo'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='bar'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) f
) perl -E" $u='baz'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='foo'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) f
) perl -E" $u='bar'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='baz'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) d
) My expectation was: smart matching of two strings uses 'eq'. $u can
) not be equal to both 'foo' and 'bar' at the same time so in the 'and'
) case I always expect the default 'd'. In the 'or' case I expect 'f' to
) be printed if $u is either 'foo' or 'bar'.
) Why is my expectation wrong?

print('foo' and 'bar'); # bar
print('foo' or 'bar'); # foo

I guess the smart matching doesn't distribute ofer the 'and' or the 'or'.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
W

Wolfram Humann

print('foo' and 'bar');  # bar
print('foo' or 'bar');   # foo

I guess the smart matching doesn't distribute ofer the 'and' or the 'or'.

Hm, sounds reasonable. However, it's not really what I expected from
the explanation for "when(EXPR)" in perlsyn:
Furthermore:
If EXPR is ... && ... or ... and ..., the test is applied
recursively to both arguments. If both arguments pass the test, then
the argument is treated as boolean.
If EXPR is ... || ... or ... or ..., the test is applied
recursively to the first argument.
These rules look complicated, but usually they will do what you
want.

As a matter of fact, if the 'and' and 'or' are evaluated before the
smart matching applies, IMHO it would be better to state exactly that
instead of saying "usually they will do what you want" :)
Thanks for the reply,
Wolfram
 
U

Uri Guttman

WH> Hm, sounds reasonable. However, it's not really what I expected from
WH> the explanation for "when(EXPR)" in perlsyn:
WH> Furthermore:
WH> If EXPR is ... && ... or ... and ..., the test is applied
WH> recursively to both arguments. If both arguments pass the test, then
WH> the argument is treated as boolean.
WH> If EXPR is ... || ... or ... or ..., the test is applied
WH> recursively to the first argument.
WH> These rules look complicated, but usually they will do what you
WH> want.

having read the docs i agree it isn't very clear. try it again with
regexes like /foo/ and /bar/ also with && instead of 'and'. i feel the
logic as the docs seem to say is $_ ~~ EXPR which makes it:

$_ ~~ 'foo' and 'bar'
that evaluates to
($_ ~~ 'foo') and 'bar'

so it won't distribute as you think (and the docs seem to imply). this
could be a bug in perl or the docs. i would raise the issue on p5p as
this definitely seems ambiguous.

also try explicit tests like $_ eq 'foo' which should work.

uri
 
S

sln

Hm, sounds reasonable. However, it's not really what I expected from
the explanation for "when(EXPR)" in perlsyn:
Furthermore:
If EXPR is ... && ... or ... and ..., the test is applied
recursively to both arguments. If both arguments pass the test, then
the argument is treated as boolean.
If EXPR is ... || ... or ... or ..., the test is applied
recursively to the first argument.
These rules look complicated, but usually they will do what you
want.

As a matter of fact, if the 'and' and 'or' are evaluated before the
smart matching applies, IMHO it would be better to state exactly that
instead of saying "usually they will do what you want" :)
Thanks for the reply,
Wolfram

Hum, hows that old given/when thing worky for ya?
Recursive boolean expression, now where has that been all these years?

-sln
 
W

Willem

Wolfram Humann wrote:
)> print('foo' and 'bar'); ?# bar
)> print('foo' or 'bar'); ? # foo
)>
)> I guess the smart matching doesn't distribute ofer the 'and' or the 'or'.
)>
)
) Hm, sounds reasonable. However, it's not really what I expected from
) the explanation for "when(EXPR)" in perlsyn:
) Furthermore:
) If EXPR is ... && ... or ... and ..., the test is applied
) recursively to both arguments. If both arguments pass the test, then
) the argument is treated as boolean.
) If EXPR is ... || ... or ... or ..., the test is applied
) recursively to the first argument.
) These rules look complicated, but usually they will do what you
) want.

Perhaps you should read back and see what 'the test' is that they are
talking about (it's the test to see if smart matching applies or not).

In your case, the test doesn't apply, and smart matching is done.
Then you get ($_ ~~ ('foo' or 'bar')), which evaluates to ($_ ~~ 'foo')

) As a matter of fact, if the 'and' and 'or' are evaluated before the
) smart matching applies, IMHO it would be better to state exactly that
) instead of saying "usually they will do what you want" :)

The bit you quoted doesn't have to do with that, it's just about deciding
when to apply smart matching or not. I guess a perl guru can give a more
detailed explanation on that.

Smart matching itself doesn't do anything special with &&, and, ||, or.
('bar' ~~ ('foo' or 'bar')) evaluates to 0.

However, to get the behaviour for 'or' that you want, you can do something
like: given($x) { when (['foo', 'bar']) { say 'f' } }


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
C

C.DeRykus

Wolfram Humann wrote:

) Would someone be so kind to explain the following (quotes are for
) win32 perl):
)
) perl -E" $u='foo'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='bar'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) f
) perl -E" $u='baz'; given($u){ when('foo' and 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='foo'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) f
) perl -E" $u='bar'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) d
) perl -E" $u='baz'; given($u){ when('foo' or 'bar'){say 'f'}
) default{say 'd'} } "
) d
) My expectation was: smart matching of two strings uses 'eq'. $u can
) not be equal to both 'foo' and 'bar' at the same time so in the 'and'
) case I always expect the default 'd'. In the 'or' case I expect 'f' to
) be printed if $u is either 'foo' or 'bar'.
) Why is my expectation wrong?

print('foo' and 'bar');  # bar
print('foo' or 'bar');   # foo

I guess the smart matching doesn't distribute ofer the 'and' or the 'or'.

That seems to be the case:

perl -MO=Deparse -E"$u='foo'; given($u){ when('foo' and 'bar'){say
'f'}
default{say 'd'} } "
BEGIN { ... }
$u = 'foo';
given ($u) {
when ('bar') {
say 'f';
}
default {
say 'd';
}
}

perl -MO=Deparse -E" $u='bar'; given($u){ when('foo' or 'bar'){
say 'f'} default{ say 'd'} } "
BEGIN { ... }
$u = 'bar';
given ($u) {
when ('foo') {
say 'f';
}
default {
say 'd';
}
}
 
U

Uri Guttman

CD> That seems to be the case:

CD> perl -MO=Deparse -E"$u='foo'; given($u){ when('foo' and 'bar'){say
CD> 'f'}
CD> default{say 'd'} } "
CD> BEGIN { ... }
CD> $u = 'foo';
CD> given ($u) {
CD> when ('bar') {

'foo' and 'bar' compile time reduce to 'bar'.


CD> say 'f';
CD> }
CD> default {
CD> say 'd';
CD> }
CD> }

CD> perl -MO=Deparse -E" $u='bar'; given($u){ when('foo' or 'bar'){
CD> say 'f'} default{ say 'd'} } "
CD> BEGIN { ... }
CD> $u = 'bar';
CD> given ($u) {
CD> when ('foo') {

'foo' or 'bar' compile time reduce to 'foo'.


CD> say 'f';
CD> }
CD> default {
CD> say 'd';
CD> }
CD> }

given (pun intended) that, i would say the docs are buggy in this
area. or at least ambiguous and should be fixed. the 'test' for type
inside the when seems to be for simple types and not complex
expressions. this makes some sense in that how would perl know which
smart match mode to use for each part of a complex boolean expression?
but the docs should explain that better as it does

In fact "when(EXPR)" is treated as an implicit smart match most
of the time. The exceptions are that when EXPR is:

so it isn't all the time that is does a smart match.

o If EXPR is "... && ..." or "... and ...", the test is applied
recursively to both arguments. If both arguments pass the test,
then the argument is treated as boolean.

that is poorly written IMO. it seems to mean (as we have learned) the
test for the TYPE is done on both boolean args. then this expression is
run just as a boolean (and that is why the deparse drops the second
boolean arg - it can't affect the boolean since the other arg is a
constant). but how would you ever implicitly invoke smart matching if
you have a boolean expression? the example in the docs shows:

when (/^\d+$/ && $_ < 75) { ... }

and that does not imply any smart matching. it is a regex against $_ and
a normal expression.

this does need some more explanation. i see a smart match tutorial in
the future (prolly not from me!).

uri
 
I

Ilya Zakharevich

constant). but how would you ever implicitly invoke smart matching if
you have a boolean expression? the example in the docs shows:

when (/^\d+$/ && $_ < 75) { ... }

and that does not imply any smart matching. it is a regex against $_ and
a normal expression.

this does need some more explanation. i see a smart match tutorial in
the future (prolly not from me!).

I think the much more productive solution is to avoid smart matching
completely. (I have no idea WHY it was added to the language; looks
like a severely not-enough-thought-about feature...)

Yours,
Ilya
 
U

Uri Guttman

IZ> I think the much more productive solution is to avoid smart matching
IZ> completely. (I have no idea WHY it was added to the language; looks
IZ> like a severely not-enough-thought-about feature...)

this isn't a smart matching issue but a when/given issue and when it
will use smart matching. if you want to bitch about a feature, then
know which is which before you bitch! :)

uri
 
I

Ilya Zakharevich

IZ> I think the much more productive solution is to avoid smart matching
IZ> completely. (I have no idea WHY it was added to the language; looks
IZ> like a severely not-enough-thought-about feature...)
this isn't a smart matching issue but a when/given issue and when it
will use smart matching. if you want to bitch about a feature, then
know which is which before you bitch! :)

So it is "smarter than smart" matching. Do you see any difference?

Ilya
 
W

Wolfram Humann

having read the docs i agree it isn't very clear. try it again with
regexes like /foo/ and /bar/ also with && instead of 'and'.

Going from 'and' and 'or' to '&&' and '||' makes no difference. '/foo/
or /bar/' works -- but only because (/foo/ or /bar/) already does what
I want without needing any given/when or smartmatching specials. When
testing for undef I need to write 'when(/foo/ or !defined($_))'. Maybe
Willem's solution below is better here.

However, to get the behaviour for 'or' that you want, you can do something
like: given($x) { when (['foo', 'bar']) { say 'f' } }

That extends nicely to when(['foo', undef]). Thanks for the idea. The
only drawback is that the intention is not as obvious because the 'or'
is implicit from the undelying 'grep'-like smartmatching.

Thanks for all replies,
Wolfram
 
U

Uri Guttman

IZ> I think the much more productive solution is to avoid smart matching
IZ> completely. (I have no idea WHY it was added to the language; looks
IZ> like a severely not-enough-thought-about feature...)

IZ> So it is "smarter than smart" matching. Do you see any difference?

yes i see the difference. given/when decides whether to do boolean or
smart matching. then smart matching may do some more decisions. fairly
obvious differences in the phases.

uri
 
I

Ilya Zakharevich

IZ> I think the much more productive solution is to avoid smart matching
IZ> completely. (I have no idea WHY it was added to the language; looks
IZ> like a severely not-enough-thought-about feature...)


IZ> So it is "smarter than smart" matching. Do you see any difference?

yes i see the difference. given/when decides whether to do boolean or
smart matching. then smart matching may do some more decisions. fairly
obvious differences in the phases.

What I meant is that the semantic of given/when is, by inheritance,
yet more baroque than one of smart matching. People are just plain
not able to juggle in mind that many logical switch tables.

IMO, one should have left only "the most obvious entries" in the
logic of smart matching [ones which can be deduced without
confusion from a VERY short list of rules], and just plain PROHIBIT
all the rest. One might have needed to be yet more strict with
given/when... (Well, the more complex semantic could have been
left on different keywords, clearly marking "this piece of code
requires special attention".)

IMO, one should have done the same with precedence tables of Perl -
one should be able to prohibit all the non-obvious confusion-prone
combinations via `use strict q(precedence)', forcing the user to use
explicit parentheses.

(The situation with RExen is kinda borderline; the complexity there is
clearly "visually marked" by "bizarre delimiters". BTW: Now, when I
added syntax highlight of RExen to CPerl, I think that this complexity
went another notch down... I would not mind 2-3 more notches down,
but I have not seen any promising idea yet...)

Yours,
Ilya
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top