I expected the refinement of the Any type to Str|True would make the name
type match any Str or True, but this is what I see:
subset name of Any where Str|True;
sub go(name :$x) {
say $x;
}
go(x => "hello"); #hello
go(x => True); #True
go(x => 2); #2
my @arr = 1, 2, 3;
go(x => @arr); #[1, 2, 3]
If I change the subset to subset name of Any where Str|Bool
, then it works as I expect:
subset name of Any where Str|Bool;
sub go(name :$x) {
say $x;
}
go(x => "hello");
go(x => True);
go(x => False);
go(x => 2);
--output:--
hello
True
False
Constraint type check failed in binding to parameter '$x'; expected name but got Int (2)
in sub go at b.raku line 19
in block <unit> at b.raku line 27
The subset name of Any where Str|True;
was in the docs for MAIN, which is the first place I encountered a subset. So, the rule seems to be that you must declare types rather than instances of a type when refining a type with a subset. But, then I tried:
subset name of Any where Str|2;
sub go(name :$x) {
say $x;
}
go(x => "hello");
go(x => 2);
go(x => 6);
--output:--
hello
2
Constraint type check failed in binding to parameter '$x'; expected name but got Int (6)
in sub go at b.raku line 19
in block <unit> at b.raku line 25
Hmmm...the following seems to be the problem with True:
[197] > @arr ~~ True
Potential difficulties:
Smartmatch against True always matches; if you mean to test the topic for truthiness, use :so or *.so or ?* instead
------> @arr ~~ ⏏True
True
[198] > 7 ~~ True
Potential difficulties:
Smartmatch against True always matches; if you mean to test the topic for truthiness, use :so or *.so or ?* instead
------> 7 ~~ ⏏True
True
[199] > False ~~ True
Potential difficulties:
Smartmatch against True always matches; if you mean to test the topic for truthiness, use :so or *.so or ?* instead
------> False ~~ ⏏True
True
Why would False match True?
Okay, according to the docs, the smartmatch operator aliases the lhs to $_, then calls rhs.ACCEPTS($_)
, and for the Bool class ACCEPTS is defined to return the invocant. Therefore, if True is on the rhs side of the smartmatch operator, ACCEPTS always returns True, and if False is on the rhs of the smartmatch operater, ACCEPTS always returns False, leading to this strange result:
[203] > False ~~ False
Potential difficulties:
Smartmatch against False always fails; if you mean to test the topic for truthiness, use :!so or *.not or !* instead
------> False ~~ ⏏False
False
The result is that False smartmatches True, but False does not smartmatch False???
That's how e.g. you can write any normal test expression in a
given
/when
and have it work; an expr that evaluates to a Bool will be used as the result of smartmatch, ignoring the "subject" of the match. Pretty expected behavior.As for how to write the type you want, how about the plain vanilla:
subset name of Any where { $_ ~~ Str || $_ ~~ Bool && ?$_ }