Skip Menu |

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

Report information
The Basics
Id: 132918
Status: resolved
Priority: 0/
Queue: Type-Tiny

People
Owner: Nobody in particular
Requestors: kaw [...] heise.de
Cc:
AdminCc:

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



Subject: Unable to use provided is_InstanceOf
Date: Wed, 1 Jul 2020 09:11:04 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
I'm trying to use is_InstanceOf, but so far have found no way to pass in the object and the name. Calling my $obj = MyObject->new; if(is_InstanceOf($obj, 'MyObject)) {…} always yields true and executes the guarded path. Looking at the code it is not clear to me how I am supposed to hand in the variable to check as well as the allowed values. The solution to this bug can be: 1. Document how to call is_InstanceOf and other checks, that allow passing in the definition of valid values. (And if required: implement a way to do this) 2. Don't export is_* methods for checks that require additional values, if they can't be passed in.
is_InstanceOf($x) is the same as InstanceOf->check($x) which is basically the same as blessed($x).
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
Date: Mon, 13 Jul 2020 07:03:01 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
On 12/07/2020 01:46, Toby Inkster via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132918 > > > is_InstanceOf($x) is the same as InstanceOf->check($x) which is basically the same as blessed($x).
Ok, that would sort of solve is_InstanceOf() but not the other checks with additional parameters, right? Or how would one use is_Enum(), for example? In any case the usage of is_InstanceOf() should at least be documented. My preferred solution would still be, that one could write is_InstanceOf($foo, 'MyObject') and get true/false back.
It does certainly make sense. Also, say: is_ArrayRef( \@integers, Int ) However, the is_Foo functions have a ($) prototype, so allowing them to take a second parameter could break backcompat in some cases. As a side-note, you can do this: use Types::Standard is_InstanceOf => { of => 'Foo', -as => 'is_Foo', }; my $obj = bless {}, "Foo"; if ( is_Foo $obj ) { print "Found a foo!\n"; } Assuming you have Type::Tiny::XS installed, the is_Foo() function will be implemented in XS so REALLY fast. Faster than checking: if ( blessed($obj) && $obj->isa("Foo") ) { print "Found a foo!\n"; } Similar speed (I need to benchmark it more) to the new Perl 5.32 isa operator: if ( $obj isa Foo ) { print "Found a foo!\n"; }
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
Date: Fri, 17 Jul 2020 12:41:32 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
Toby Inkster via RT wrote on 17.07.20 12:21: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132918 > > > It does certainly make sense. Also, say: > > is_ArrayRef( \@integers, Int ) > > However, the is_Foo functions have a ($) prototype, so allowing them to take a second parameter could break backcompat in some cases.
Would the backward compatibility be maintained if you allowed such a second parameter only for tests like is_Enum, which don't make any sense without the second parameter? is_ArrayRef(\@params, Int) would be nice too, but I can very well cope with is_ArrayRef(\@params) && all {is_Int($_)} @params) as a construct. Show quoted text
> As a side-note, you can do this: > > use Types::Standard is_InstanceOf => { > of => 'Foo', > -as => 'is_Foo', > }; > > my $obj = bless {}, "Foo"; > > if ( is_Foo $obj ) { > print "Found a foo!\n"; > } > > Assuming you have Type::Tiny::XS installed, the is_Foo() function will be implemented in XS so REALLY fast. Faster than checking: > > if ( blessed($obj) && $obj->isa("Foo") ) { > print "Found a foo!\n"; > } > > Similar speed (I need to benchmark it more) to the new Perl 5.32 isa operator: > > if ( $obj isa Foo ) { > print "Found a foo!\n"; > }
Thanks, I'll look into this. The isa operator is not yet available to me reliably, but the rest should be possible.
Show quoted text
> is_ArrayRef(\@params) && all {is_Int($_)} @params)
If @params has more than, say, 10 integers, then you'll probably find this to be faster: ArrayRef->of(Int)->check( \@params ) I've also been working lately on something like: Int->all( @params ) # => bool Int->any( @params ) # => bool my @ints = Int->grep( @params ) # => list of ints And: my $Rounded = Int->plus_coercions(Num, 'int($_)'); my @ints = $Rounded->map( @numbers ); I will think about adding is_InstanceOf($obj, $class) but more likely I'll just document that for some parameterized types, the is_* functions aren't very useful. is_InstanceOf = is_Object is_HasMethods = is_Object is_Enum = is_Str is_StrMatch = is_Str and so on.
I've now released isa.pm which is separate from Type::Tiny (but will hook into Type::Tiny::XS if it's available) that lets you do this: use isa 'MyObject'; my $obj = MyObject->new; if ( isa_MyObject $obj ) { ...; } It is way faster than a two-argument form of is_InstanceOf could ever be, and even twice the speed of the Perl 5.32 native isa operator.
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
Date: Mon, 7 Sep 2020 06:58:57 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
On 04/09/2020 22:31, Toby Inkster via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132918 > > > I've now released isa.pm which is separate from Type::Tiny (but will hook into Type::Tiny::XS if it's available) that lets you do this: > > use isa 'MyObject'; > > my $obj = MyObject->new; > if ( isa_MyObject $obj ) { > ...; > } > > It is way faster than a two-argument form of is_InstanceOf could ever be, and even twice the speed of the Perl 5.32 native isa operator.
Thank you very much, that looks very promising! With regards to a construct like ArrayRef->of(Int)->check( \@params ) from your previous E-Mail: yeah, that is a good advice and I would expect the is_* methods to map to that, if they are possible. In any case: thanks a lot!
I was pretty convinced that the is_ functions were prototyped ($) so allowing them to accept a second argument would break stuff. Turns out that the is_ functions don't have prototypes, so it shouldn't break anything that assumed a prototype of ($). It's very easy to implement. (About 4 new lines of code, and a change to one existing line.) However, it has one big drawback. Currently checks like is_ArrayRef, is_HashRef, etc can be done using an XS sub. To allow is_ArrayRef($foo, Int) to work, they'd need to be wrapped in a Perl sub, making them much slower. Before the change, is_Object(undef) and is_InstanceOf(undef) run at the same speed: [tai@titania pts/5 p5-type-tiny]$ perl bench.tmp Rate is_Object is_InstanceOf is_Object 24439618/s -- -2% is_InstanceOf 24922676/s 2% -- After the change, is_InstanceOf(undef) gets slowed right down! [tai@titania pts/5 p5-type-tiny]$ perl -Ilib bench.tmp Rate is_InstanceOf is_Object is_InstanceOf 4633858/s -- -81% is_Object 24439618/s 427% -- Slowing down is_InstanceOf isn't a huge issue really, because people still have a fast is_Object. But slowing down is_ArrayRef and is_HashRef are a big no from me.
I did also have the idea of making it opt-in, like: use Types::Standard -autoparam, qw( is_InstanceOf ); But then if you see `is_InstanceOf` in code, you need to scroll up to find the `use` statement to figure out which version of the function you're dealing with, and I don't like that idea.
Perhaps having a general "is()" function would be useful? use strict; use warnings; use feature 'say'; { my %cache; sub is { my $type = shift; my $caller = caller; my $check = ( $cache{$caller}{$type} ||= do { require Type::Utils; my $type_object = Type::Utils::dwim_type($type, for => $caller); if ( ! $type_object ) { require Carp; Carp::confess("Cannot find type $type; failed"); return !!0; } $type_object->compiled_check; } ); goto $check if @_==1; $check->($_) || return !!0 for @_; return !!1; } } say is( 'ArrayRef' => [] ); say is( 'InstanceOf[Bleh]' => bless({}, 'Bleh') );
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
Date: Tue, 8 Sep 2020 07:03:21 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
On 07/09/2020 14:22, Toby Inkster via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=132918 > > > Perhaps having a general "is()" function would be useful? > > use strict; > use warnings; > use feature 'say'; > > { > my %cache; > sub is { > my $type = shift; > my $caller = caller; > my $check = ( $cache{$caller}{$type} ||= do { > require Type::Utils; > my $type_object = Type::Utils::dwim_type($type, for => $caller); > if ( ! $type_object ) { > require Carp; > Carp::confess("Cannot find type $type; failed"); > return !!0; > } > $type_object->compiled_check; > } ); > goto $check if @_==1; > $check->($_) || return !!0 for @_; > return !!1; > } > } > > say is( 'ArrayRef' => [] ); > say is( 'InstanceOf[Bleh]' => bless({}, 'Bleh') );
Yeah, this would be quite good too. Sure the sugar of saying is_Foo is really nice, but if that's impossible to do fast, then I would certainly vote for something like this, which is still very easy to read (though the non-functional is_* methods should still be removed/no longer be exported or at the very least documented as "don't do what you expect"). The is() method would be a wonderful addition IMHO.
Download OpenPGP_0x4142C9A807C9D0B9.asc
application/pgp-keys 7k

Message body not shown because it is not plain text.

Download OpenPGP_signature
application/pgp-signature 840b

Message body not shown because it is not plain text.

https://metacpan.org/release/TOBYINK/Type-Tiny-1.011_002 use Types::Standard qw( ArrayRef Int ); use Type::Utils qw( is ); if ( is ArrayRef[Int], \@numbers ) { say "It's all integers!\n"; } Or even: use Types::Standard qw( Int ); if ( Int->all(@numbers) ) { say "It's all integers!\n"; }
Subject: Re: [rt.cpan.org #132918] Unable to use provided is_InstanceOf
Date: Wed, 23 Sep 2020 08:39:49 +0200
To: bug-Type-Tiny [...] rt.cpan.org
From: Kai Wasserbäch <kaw [...] heise.de>
Thank you so much, this is very helpful!
Released Type::Utils 1.012000 with an exported `is` function. Also released isa.pm.