Skip Menu |

This queue is for tickets about the future CPAN distribution.

Report information
The Basics
Id: 93164
Status: resolved
Priority: 0/
Queue: future

People
Owner: Nobody in particular
Requestors: frioux [...] gmail.com
Cc:
AdminCc:

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



Subject: then doesn't seem to check it's input
In this simple example the non-sub passed to then gets silently ignored: use warnings; use IO::Async::Loop; use Future; use Future::Utils 'repeat'; my $loop = IO::Async::Loop->new; sub periodic_future { my ($loop, $period, $cb) = @_; $loop->delay_future(after => $period / 2) ->then( repeat { $loop->delay_future(after => $period) ->then($cb) } while => sub { 1 } ) } Future->wait_all( periodic_future($loop, 1, sub { say 'woo!'; Future->wrap }), periodic_future($loop, 2, sub { say 'bang.'; Future->wrap }), )->get;
Hmm. I'm not currently aware of what's the best practice to test if something is callable, without actually calling it. ref $thing eq "CODE" won't do, because it's possible, however ill-advised, to bless a CODE reference, and after that it's still callable (maybe you wanted to put a DESTROY handler on it or some odd thing?). Also it's possible for any other object to gain functionification overload magic via use overload '&{}'. -- Paul Evans
On Wed Feb 19 20:30:19 2014, PEVANS wrote: Show quoted text
> Hmm. > > I'm not currently aware of what's the best practice to test if > something is callable, without actually calling it.
#p5p suggests reftype($cb) eq 'CODE' or overload::Method($cb, '&{}') I think that looks good enough. I'll sprinkle some testing of that nature around the place... -- Paul Evans
On Wed Feb 19 20:54:54 2014, PEVANS wrote: Show quoted text
> I think that looks good enough. I'll sprinkle some testing of that > nature around the place...
$ perl -Mblib -MFuture -E 'Future->new->then( [] )->on_done(sub{})' Expected $code to be callable in ->then at -e line 1. -- Paul Evans
Subject: rt93164.patch
=== modified file 'lib/Future.pm' --- lib/Future.pm 2014-02-20 00:58:50 +0000 +++ lib/Future.pm 2014-02-20 02:13:52 +0000 @@ -12,9 +12,12 @@ our $VERSION = '0.23'; use Carp qw(); # don't import croak -use Scalar::Util qw( weaken blessed ); +use Scalar::Util qw( weaken blessed reftype ); use B qw( svref_2object ); +# we are not overloaded, but we want to check if other objects are +require overload; + our @CARP_NOT = qw( Future::Utils ); use constant DEBUG => $ENV{PERL_FUTURE_DEBUG}; @@ -204,6 +207,12 @@ sprintf "%s(%s line %d)", $cv->GV->NAME, $cop->file, $cop->line; } +sub _callable +{ + my ( $cb ) = @_; + reftype($cb) eq 'CODE' or overload::Method($cb, '&{}') +} + sub new { my $proto = shift; @@ -854,6 +863,9 @@ my $func = (caller 1)[3]; $func =~ s/^.*:://; + $flags & (CB_SEQ_IMDONE|CB_SEQ_IMFAIL) or _callable( $code ) or + Carp::croak "Expected \$code to be callable in ->$func"; + if( !defined wantarray ) { Carp::carp "Calling ->$func in void context"; } @@ -938,6 +950,11 @@ return $self->_sequence( $done_code, CB_SEQ_ONDONE|CB_RESULT ); } + !$done_code or _callable( $done_code ) or + Carp::croak "Expected \$done_code to be callable"; + !$fail_code or _callable( $fail_code ) or + Carp::croak "Expected \$fail_code to be callable"; + # Complex return $self->_sequence( sub { my $self = shift;
This was released in 0.24 -- Paul Evans