[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