Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 113395
Status: rejected
Priority: 0/
Queue: Moose

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

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



Subject: How to produce proper error msg when Type coercion fails due to user-defined constraint
Date: Sun, 27 Mar 2016 22:40:40 -0700
To: bug-moose [...] rt.cpan.org
From: Jim Avera <jim.avera [...] gmail.com>
Hello, I'm trying to write something which will make Moose classes "just work" when used by programs which happen to have "use bigint" or similar in scope. Classes defined using Moose do not work by default, if attributes use type Int or Num, because ordinary literal numbers like 42 in the calling program are compiled into Math::BigInt (or BigFloat or BigRat) when "use big*" is in effect. The goal is to auto-convert Math::Big* values so they can be passed for Int or Num attributes, and issue a comprehensible error message if the value can not be converted without loss of information. I tried creating a subtype with a "where" clause which checks that the value is convertible, and then define a coercion from that subtype to Int. However it appears that the subtype is simply _ignored_ if the "where" clause fails, rather than causing an error using the subtype's message {...} . The result is that if the value it too large, a generic "wrong type" error occurs which is confusing. I tried doing the range check inside the "via" code of the coerce, and die'ing if the test failed. This made my error message appear, but without any context, i.e., without indicating where in the program the error occurred or which attribute had the bad value. ==> So: Is there a way for a *coerce* to throw an error which will be displayed with context information, or alternatively, to _force_ a coerce to execute a subtype cast such that if the "where" condition of the subtype fails, then the "message" from the subtype is displayed? use Moose::Util::TypeConstraints; subtype 'CoercableBigInt', as 'Math::BigInt', where { use bigint; abs($_) < 0x7fffffff }, message { "$_ is too large to coerce to Int" } # this message does NOT appear ; coerce 'Int', from 'CoercableBigInt', via { $_->numify() }; package MyClass; use Moose; has 'i' => (is => 'rw', isa => 'Int', coerce => 1); package main; use bigint; # this works, as expected my $obj = MyClass->new(i => 42); # This produces a confusing generic "wrong type" error, not the # message in the message{...} block of the CoercableBigInt subtype my $obj2 = MyClass->new(i => 42*1000000*1000000);
On 2016-03-27 22:40:51, jim.avera@gmail.com wrote: Show quoted text
> ==> So: Is there a way for a *coerce* to throw an error which will be > displayed with context information, or alternatively, to _force_ a > coerce to execute a subtype cast such that if the "where" condition > of the subtype fails, then the "message" from the subtype is displayed?
You can invoke the interfaces of the type constraint directly, and capture the message that way -- see the documentation in Moose::Meta::TypeConstraint. my $type = Moose::Util::type_constraints::find_type_constraint('MyType'); my $error_message = $type->validate($value); I'm marking this ticket as rejected because it's not really a bug. If you have questions, feel free to follow up on the moose mailing list (http://lists.perl.org/list/moose.html); you can also find someone during most North American and European waking hours on irc (irc.perl.org #moose). good luck!
From: jim.avera [...] gmail.com
On Mon Mar 28 13:24:48 2016, ETHER wrote: Show quoted text
> You can invoke the interfaces of the type constraint directly, and > capture the message that way -- see the documentation in > Moose::Meta::TypeConstraint.
Hi, Could you say a few bits more about that? Where exactly should such code go -- in the 'where' clause of the subtype or the 'via' clause of the coerce? And note that I don't want to capture the error message, I want to PROVIDE the error message (and have it print with context info). I would have thought that the message {...} clause in the subtype definition would have DWIM, but it is not being used for some reason. Which I thought might be a bug... Thanks.
On 2016-03-28 11:00:02, jim.avera@gmail.com wrote: Show quoted text
> On Mon Mar 28 13:24:48 2016, ETHER wrote:
> > You can invoke the interfaces of the type constraint directly, and > > capture the message that way -- see the documentation in > > Moose::Meta::TypeConstraint.
> > Hi, Could you say a few bits more about that? Where exactly should > such code go -- in the 'where' clause of the subtype or the 'via' > clause of the coerce? And note that I don't want to capture the > error message, I want to PROVIDE the error message (and have it print > with context info). > > I would have thought that the message {...} clause in the subtype > definition would have DWIM, but it is not being used for some reason. > Which I thought might be a bug...
It's not a bug. You were correct here: Show quoted text
> However it appears that the subtype is simply _ignored_ if the "where" clause fails...
CoercableBigInt isn't a *sub*type of int - it's a supertype. Type checks are done in order from type->subtype (parent->child), so if the type constraint fails the parent (Int), it doesn't check the subtypes. You'll have to define your bigint type independently of Int.
Subject: Re: [rt.cpan.org #113395] How to produce proper error msg when Type coercion fails due to user-defined constraint
Date: Mon, 28 Mar 2016 15:41:52 -0700
To: bug-Moose [...] rt.cpan.org
From: Jim Avera <jim.avera [...] gmail.com>
On 03/28/2016 12:33 PM, Karen Etheridge via RT wrote: Show quoted text
> CoercableBigInt isn't a *sub*type of int - it's a supertype. Type checks are done in order from type->subtype (parent->child), so if the type constraint fails the parent (Int), it doesn't check the subtypes. > > You'll have to define your bigint type independently of Int.
Ok, thanks. Then it looks to be impossible to use innocent Moose classes in applications which "use bignum" etc. (if I understand you correctly, every Moose class used by the app would have to be modified to use custom types instead of 'Int' and 'Num') -Jim
On 2016-03-28 15:42:02, jim.avera@gmail.com wrote: Show quoted text
> On 03/28/2016 12:33 PM, Karen Etheridge via RT wrote:
> > CoercableBigInt isn't a *sub*type of int - it's a supertype. Type > > checks are done in order from type->subtype (parent->child), so if > > the type constraint fails the parent (Int), it doesn't check the > > subtypes. > > > > You'll have to define your bigint type independently of Int.
> > Ok, thanks. Then it looks to be impossible to use innocent Moose > classes in > applications which "use bignum" etc. > > (if I understand you correctly, every Moose class used by the app > would > have to be modified to use custom types instead of 'Int' and 'Num')
The alternative is to totally redefine the Int and Num types so they can be bigints. This is doable, as the type definitions are straightforward, in Moose::Util::TypeConstraints::Builtins -- but will affect everything else in the same runtime instance (and probably break things like MooseX::Storage unless it was also adjusted), so must be done with great care.