[Perl5-syntax] How to test for a role in a method signature

Piers Cawley pdcawley at bofh.org.uk
Sat Mar 5 07:43:37 GMT 2011


On Sat, Mar 5, 2011 at 3:23 AM, Reverend Chip <rev.chip at gmail.com> wrote:
> On 3/4/2011 4:00 PM, Piers Cawley wrote:
>> On Fri, Mar 4, 2011 at 7:24 PM, Reverend Chip <rev.chip at gmail.com> wrote:
>>> On 3/4/2011 3:06 AM, Piers Cawley wrote:
>>>> On Fri, Mar 4, 2011 at 10:29 AM, Reverend Chip <rev.chip at gmail.com> wrote:
>>>>> On 3/4/2011 1:57 AM, Piers Cawley wrote:
>>>>>> On Fri, Mar 4, 2011 at 7:16 AM, Reverend Chip <rev.chip at gmail.com> wrote:
>>>>>>> On 3/3/2011 10:32 PM, Piers Cawley wrote:
>>>>>>>> Personally, I prefer the flow of 'Typed $parameter does coerce', where
>>>>>>>> the constraint declaration is always to the left of the parameter name
>>>>>>>> and the right hand side is for declaring stuff about how the parameter
>>>>>>>> is initialized. I would encourage anyone wanting to constrain by type
>>>>>>>> to declare a type along the lines of "subtype DoesRole, as role_type
>>>>>>>> 'Role'" ...
>>>>>>> No, I don't buy it.  The "isa" and "does" tests are so fundamental and
>>>>>>> common that forcing people to type that much to get the test would
>>>>>>> violate Huffman.
>>>>>> That's why I think that the better solution is to delegate to the
>>>>>> package to find out if a particular value satisfies it. If the package
>>>>>> is a class, then obviously it does an 'isa' test, if a role, then it
>>>>>> does a 'does' check and, if a type constraint, it uses the type's
>>>>>> constraints.
>>>>> And for combining?  You only get one name to the left.
>>>> If you _really_ want to ensure that a parameter isa Foo and also does
>>>> Bar then you need to rethink your architecture. Or hide the pain, bite
>>>> the bullet and make a custom type.
>>>>
>>>> Easy things should be easy. Hard things should be possible. Stupid
>>>> things should be discouraged.
>>> I was thinking of does Foo and does Bar, actually.  But there is no way
>>> at compile time to know which test will apply, so your proposal is
>>> slower at runtime.  That's a killer.
>> And down that road lies C++. Let the constraint (be it a role, a class
>> or a moose type) decide what tests to run. You pay the cost of a
>> method call and get more convenient syntax. How do you plan to signal
>> that a parameter should be coerced?
>
> Let me first observe that this is a fundamental separation in how people
> generally see function declarations - it happened with C, and it's
> happening here.  Should they be descriptive or coercive?  Should they
> just examine the values, or modify them?  In C, the coercive won, and on
> balance I think that was OK.  But I favor the descriptive as default in
> Perl, because Perl doesn't make programmers make trivial things like
> integer size emerge as types; Perl coercions are heavyweight and so we
> should have to ask for them.  Therefore in my world, coercion would not
> be the default ... though all is fair if you predeclare.
>
> So I would propose:
>    use Method::Signatures { coerce => 1 };   # to change the default
> and
>    method foo (Int $x is coerced)   # if it's not the default
>    method foo (Int $x is uncoerced)   # to reverse a default
> I'm sure I could come up with something more clever but that's what I
> see now.

Obviously coercion shouldn't be the default, but something asked for
on a per parameter basis. The point I'm trying to make is that the
constraint side of a parameter is already polymorphic - in general you
can't know if it's a type or a class at compile time (unless it's
coerced, in which case it must be a type) so allowing for specifying a
Role as a constraint shouldn't cost any more. By doing so you make the
code more resilient when some class Foo becomes a role. Or maybe you
have a Role that becomes a type because you need to coerce it at some
point or another (but not in every case). It would seem inconsistent
if, in one place you had:

class BadExample {
    use TypeLib qw(Foo);

    method coercive(Foo $param is coerced) {
        ...
    }
}

class WorseExample {

    method descriptive($param does Foo) {
        ...
    }
}

And that's before you consider folks like me who have a  largish body
of work done with MX::Declare, which (I believe, I've never tried
using a bare role) expects you to introduce a new type when
constraining to a role, but which has a coercion syntax of:

method thing(ClassOrType $param does coerce) { ... }

And what looks like a drop in replacement requires me to change every
method definition that uses coercion and, for bonus points, doesn't
complain until runtime when I miss one.

Please don't break backward compatibility with MX::D and MXMS for such
a common case.



More information about the Perl5-syntax mailing list