Skip Menu |

This queue is for tickets about the Type-Tiny CPAN distribution.

Report information
The Basics
Id: 132733
Status: rejected
Priority: 0/
Queue: Type-Tiny

People
Owner: Nobody in particular
Requestors: kfm [...] plushkava.net
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Bool constraint permitting invalid values
This does not seem right. $ perl -MType::Params=validate -MTypes::Standard=Bool -E 'sub f { say validate(\@_, Bool); }; f(0); f(1); f(2); f(qr//); f({}); f([]); f(\*STDOUT)' 0 1 1 1 1 1 1 That's as tested on Linux with perl-5.30.1 and macOS with perl-5.30.0, both of which have Type::Tiny 1.010002 and Type::Tiny::XS 0.017.
On 2020-05-29T05:36:49+01:00, kfm@plushkava.net wrote: Show quoted text
> This does not seem right. > > $ perl -MType::Params=validate -MTypes::Standard=Bool -E 'sub f { say > validate(\@_, Bool); }; f(0); f(1); f(2); f(qr//); f({}); f([]); > f(\*STDOUT)' > 0 > 1 > 1 > 1 > 1 > 1 > 1 > > That's as tested on Linux with perl-5.30.1 and macOS with perl-5.30.0, > both of which have Type::Tiny 1.010002 and Type::Tiny::XS 0.017.
$ perl -MTypes::Standard=is_Bool -E 'sub f { say is_Bool($_[0])?1:0; }; f(0); f(1); f(2); f(qr//); f({}); f([]); f(\*STDOUT)' 1 1 0 0 0 0 0 $ perl -MType::Params=validate -MTypes::Standard=Bool -E 'sub f { say validate(\@_, Bool->no_coercions); }; f(0); f(1); f(2); f(qr//); f({}); f([]); f(\*STDOUT)' 0 1 Value "2" did not pass type constraint "Bool" (in $_[0]) at -e line 1 "Bool" is a subtype of "Bool" Value "2" did not pass type constraint "Bool" (in $_[0]) "Bool" is defined as: (!ref $_ and (!defined $_ or $_ eq q() or $_ eq '0' or $_ eq '1'))
On Fri May 29 02:26:59 2020, TOBYINK wrote: Show quoted text
> On 2020-05-29T05:36:49+01:00, kfm@plushkava.net wrote:
> > This does not seem right. > > > > $ perl -MType::Params=validate -MTypes::Standard=Bool -E 'sub f { say > > validate(\@_, Bool); }; f(0); f(1); f(2); f(qr//); f({}); f([]); > > f(\*STDOUT)' > > 0 > > 1 > > 1 > > 1 > > 1 > > 1 > > 1 > > > > That's as tested on Linux with perl-5.30.1 and macOS with perl- > > 5.30.0, > > both of which have Type::Tiny 1.010002 and Type::Tiny::XS 0.017.
> > > $ perl -MTypes::Standard=is_Bool -E 'sub f { say is_Bool($_[0])?1:0; > }; f(0); f(1); f(2); f(qr//); f({}); f([]); f(\*STDOUT)' > 1 > 1 > 0 > 0 > 0 > 0 > 0 > > > $ perl -MType::Params=validate -MTypes::Standard=Bool -E 'sub f { say > validate(\@_, Bool->no_coercions); }; f(0); f(1); f(2); f(qr//); > f({}); f([]); f(\*STDOUT)' > 0 > 1 > Value "2" did not pass type constraint "Bool" (in $_[0]) at -e line 1 > "Bool" is a subtype of "Bool" > Value "2" did not pass type constraint "Bool" (in $_[0]) > "Bool" is defined as: (!ref $_ and (!defined $_ or $_ eq q() or $_ > eq '0' or $_ eq '1'))
Well, thanks. It really took me by surprise. If you don't mind my asking, what is the use case for this constraint? Having read your response, I've been trying to think of a situation in which this is obviously useful but am struggling to do so. To put it another way, why wouldn't a user just use Any and proceed to check for truthiness at that point, or coerce/transform it themselves if the representation has to be just so?
Sorry, I meant "for this coercion" in the prior comment.
The Bool type constraint accepts the following values: undef "" 0 1 It is also able to coerce from any value (it just does !!$value). Why use it instead of just using Any? Well, Bool makes your intention clearer to people reading your code. If you use Any, people are going to need to check further to see how the variable is used; if you use Bool, they know you'll be checking its truthiness.
On Fri May 29 13:28:16 2020, TOBYINK wrote: Show quoted text
> The Bool type constraint accepts the following values: > > undef > "" > 0 > 1
So the manual states. But it falls down in practice due to the default coercion. Show quoted text
> > It is also able to coerce from any value (it just does !!$value).
I may not be the greatest Perl programmer but I understood your initial explanation-by-example. I was not aware of this coercion prior to opening the ticket. Mea culpa. The thing is that it explains the how, but not the why, of it. Why is this coercion applied by default for a type named Bool? What is the use case and who benefits? Is it truly necessary to be so very permissive and munge any random value into either 0 or 1 by default? I just can't envisage any situation from hereon in which I am now not going to now write Bool->no_coercions every time. There is no world in which I would want to accidentally pass an empty arrayref, say, and have it not only be tolerated but munged into a truthy value. As Perl has no native boolean data type, what I actually want is to guarantee that the caller is passing a value that is _conventionally_ used to denote something truthy or falsey, this preventing errors of logic (I'm sure that you can readily conceive of many such scenarios in the blink of an eye). The explanation of the Bool type in the manual made me think that this was what I was getting by default. To eventually find otherwise was an unwelcome surprise. Show quoted text
> > Why use it instead of just using Any?
No, I mean: why have have a type named Bool that features a default coercion that effectively makes it accept absolutely anything and evaluate as 1 for a very wide range of possible input values, then be exepected to favour _that_ over Any in principle? Surely you can see how this might be considered a pitfall, or confusing at the least? As I wrote this, I thought "I can't be the only one!" and, sure enough, only then did I realise that this issue has actually been raised before. Show quoted text
> > Well, Bool makes your intention clearer to people reading your code.
Yes. I'm not disputing this. Show quoted text
> If you use Any, people are going to need to check further to see how > the variable is used; if you use Bool, they know you'll be checking > its truthiness.
Ditto. That's one of the reasons that I'm trying to use the Bool type in the first place, just not the main reason. If I see Any in a signature then at least I know that any value is permitted to pass. Granted, it won't 'document' whether or not I intend to evaluate it for truthiness but, as far as type validation is concerned (what I'm using Type::Tiny for in the first place!) it does document what will _actually_ happen, which is to allow any value to pass. That's honest. I just don't expect a type named Bool to allow any value to pass, regardless of the underlying design decision that made it so. The !!$value transformation is not the exact sort of nannying I was looking for and I cannot fathom it as a design decision. Further, I suspect that this will be true of some others that discover Type::Tiny in the future, though I anticipate that you will not agree. In any case, I would suggest that this pitfall be mentioned in the section of the manual where Bool is introduced and described, so as to reduce the likelihood of others making this same mistake. I have my solution in so far as the unwanted coercion can be disabled and I can live with that, given that Type::Tiny is a valuable module and one with no credible competition. Finally, lest I appear ungrateful, thank you for your continued work on the module.