Skip to content

Please add ->check_coerce method which returns undef if coercion fails #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
tobyink opened this issue Jan 9, 2021 · 9 comments
Open
Milestone

Comments

@tobyink
Copy link
Owner

tobyink commented Jan 9, 2021

Migrated from rt.cpan.org #133814 (status was 'open')

Requestors:

From [email protected] on 2020-11-26 17:10:22
:

The subject pretty much says it all. There is ->coerce which returns the
original value if coercion fails, and ->assert_coerce which dies if
coercion fails but no middle ground which returns false if coercion fails.

It is true that it would just be sugar for Type->check(
Type->coerce($value) ) but it would be very useful sugar, because frankly
those nested calls are ugly, especially when it's inside an if test which
is commonly the case, and even more so in case you use a coercion object:
Coercion->type_constraint(Coercion->coerce($value))! I'm tempted to use try
{ Foo->assert_coerce($value) } but that is really even more ugly, although
less to type.

I can try to make a pull request if it would be welcome.

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] (@karenetheridge) on 2020-11-26 18:42:18
:

On 2020-11-26 09:10:22, [email protected] wrote:

The subject pretty much says it all. There is ->coerce which returns the
original value if coercion fails, and ->assert_coerce which dies if
coercion fails but no middle ground which returns false if coercion fails.

FWIW, there is no such interface in Moose::Meta::TypeConstraint, which Type::Tiny emulates (so as to allow for seamless replacement of Moose types with Type::Tiny types in Moose classes).

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] on 2020-11-26 19:44:35
:

Den tors 26 nov. 2020 19:43Karen Etheridge via RT [email protected]
skrev:

<URL: https://rt.cpan.org/Ticket/Display.html?id=133814 >

On 2020-11-26 09:10:22, [email protected] wrote:

The subject pretty much says it all. There is ->coerce which returns the
original value if coercion fails, and ->assert_coerce which dies if
coercion fails but no middle ground which returns false if coercion
fails.

FWIW, there is no such interface in Moose::Meta::TypeConstraint, which
Type::Tiny emulates (so as to allow for seamless replacement of Moose types
with Type::Tiny types in Moose classes).

So what? Moose won't use the method so no harm if it exists. Type::Tiny has
other methods without a Moose counterpart, notably ->assert_return, which
makes sense because Type::Tiny can conveniently be used to validate and
coerce any value anywhere, not just in Moo(se) attribute declarations. In
those cases these "extra" methods make sense.

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] on 2020-11-30 01:03:12
:

I have thought for a while of adding a default coercion to Maybe[Foo] whenever Foo has a coercion.

So then you could do:

my $coerced_value_or_undef = Maybe->of(Foo)->coerce($orig_value);

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] on 2020-11-30 16:22:53
:

On 2020-11-30 02:03, Toby Inkster via RT wrote:

<URL: https://rt.cpan.org/Ticket/Display.html?id=133814 >

I have thought for a while of adding a default coercion to Maybe[Foo] whenever Foo has a coercion.

So then you could do:

my $coerced_value_or_undef = Maybe->of(Foo)->coerce($orig_value);

I like it, except that if it is to be used more than once that
Maybe->of(Foo) needs to be stored somewhere. I guess that's what state
variables are for, but it is one more thing to keep track of.

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] on 2020-12-01 17:34:57
:

Type::Tiny does internally cache the result of $type1->of($type2) to avoid a lot of the internal construction stuff the second time it's called. Of course, sticking it in a state variable and reusing it will be even better.

Like the following should output the same refaddr twice:

use strict;
use warnings;
use feature 'say';
use Scalar::Util 'refaddr';
use Types::Standard -types;

my $x = Maybe->of( Int );
say refaddr( $x );

undef $x;

my $y = Maybe->of( Int );
say refaddr( $y );

@tobyink
Copy link
Owner Author

tobyink commented Jan 9, 2021

From [email protected] on 2020-12-03 09:15:19
:

Den tis 1 dec. 2020 18:35Toby Inkster via RT [email protected]
skrev:

<URL: https://rt.cpan.org/Ticket/Display.html?id=133814 >

Type::Tiny does internally cache the result of $type1->of($type2) to avoid
a lot of the internal construction stuff the second time it's called.

OK, good to know. I usually meticulously save my derived types under a new
name or in a variable but this can make things easier.

Of course, sticking it in a state variable and reusing it will be even

better.

It also reduces the amount of typing in the long run even if the derived
type is called $MaybeInt, give or take a sigil.

Like the following should output the same refaddr twice:

use strict;
use warnings;
use feature 'say';
use Scalar::Util 'refaddr';
use Types::Standard -types;

my $x = Maybe->of( Int );
say refaddr( $x );

undef $x;

my $y = Maybe->of( Int );
say refaddr( $y );

@tobyink tobyink added this to the 1.14.0 milestone Jun 6, 2022
@tobyink
Copy link
Owner Author

tobyink commented Jun 8, 2022

Hmmm, I dunno.

package Foo {
  use Moo;
  use Types::Standard -types;
  has n => (
    is => 'ro',
    isa => Maybe[Int],
    coerce => 1,
  );
}

say Foo->new( n => 1.1 )->n;

Is this not dying counter-intuitive?

I'm gonna move this back to an unsure status.

@tobyink tobyink removed this from the 1.14.0 milestone Jun 8, 2022
@SineSwiper
Copy link

+1 on this feature. I was going to create this exact issue, with this exact method name, but it's already open.

I find myself constantly using checks like Type->check( Type->coerce($val) ), but it is bulky, unintuitive, and might fail if there is no coercion. Something like Type->check_coerce($val) would be much better.

@tobyink tobyink added this to the 2.10.0 milestone Apr 16, 2025
@SineSwiper
Copy link

This should work:

sub check_coerce {
    my $self = shift;
    return $_[0] if $self->check( @_ );
    
    if ($self->has_coercion) {
        my $result = $self->_assert_coercion->coerce( @_ );
        return $result if $self->check( $result );
    }

    return;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants