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

Michael G Schwern schwern at pobox.com
Sun Mar 6 02:54:09 GMT 2011


First of all, whether types should automatically coerce is a separate and
complicated issue.  Have that out in another thread please.

As to preserving "does trait" and making that unified signature syntax...

Given that...
* the choice to use MXMS or MS is lexical

Therefore...
* Changing MS has no direct effect on MXMS or MXD users

Given that...
* "is coerce" does the same thing
* it's a trivial s{does coerce}{is coerce} to change over
* That we can see, "does coerce" is almost never used

http://www.google.com/codesearch?hl=en&lr=&q=%22does%20coerce%22+lang%3Aperl&btnG=Search

Therefore...
* Porting is a trivial code change and can be done a class at a time
* Even eliminating "does coerce" from MXMS will effect only a handful
  of users

So preserving compatibility with MXMS is not a strong argument for making
"does" a synonym for "is" unified syntax.


As to the value of "does trait" as syntax...
* Using "does" to declare a trait overloads its meaning (roles and traits)
* the meaning of "does" is stronger and more important as declaring a
  role rather than more grammatically correct synonym to declare a trait
* Perl 6 uses "does" these days to exclusively refer to roles
* Perl 6 uses "is" and "will" on parameter traits, not "does" and
  "will coerce" is grammatically correct
  http://perlcabal.org/syn/S06.html#Properties_and_traits
* Perl 6 class declarations do pretty much what was proposed
  "class Match is Regex::Match is Cool does Positional does Associative"

I find it's valuable to...
* simplify the meaning of "does" to apply just to roles
* unify with Perl 6 (who probably changed "does trait" to "will trait"
  for exactly this reason)

I'm quite happy to drop "does" for traits and use it exclusively for roles.


As to the question of how to declare a parameter does a role...

* I fully agree that roles must be as easy to use as types and classes.
* There is certainly value in declaring that a parameter does more than
  one role.
* The meaning of "Some::Thing $param" is already overloaded and ambiguous.
  It can be a type, it can be a class, and now it's suggested it could be
  a role as well.

To the last point, Piers' argument that the ambiguity is desirably as it makes
refactoring from a class to a role easier... it has some merit.

Using Moose I've had plenty of times when that ambiguity has bitten me in the
ass.  So I'd like an explicit syntax when I want to avoid the ambiguity.

(There's also the runtime overhead of checking possibly three different ways
if a parameter matches the "class/type/role", but you can eliminate that by
caching which of a class, type or role a thing turned out to be.)

So I propose both.

    method foo (Some::Class $thing)		# ambiguous
    method foo ($thing isa Some::Class)		# explicit

    method foo (Some::Type $thing)		# ambiguous
    method foo ($thing type Some::Type)		# explicit

    method foo (Some::Role $thing)		# ambiguous
    method foo ($thing does Some::Role)		# explicit

This allows multiple roles:

    method log_to_screen ($logger does Logging does Printing)

And, if you really want to, combining inheritance an roles:

    method log_to_screen ($thing isa Logger does Printing)

And you can choose between ambiguity or explicitness.



On 2011.3.5 6:43 PM, Piers Cawley wrote:
> 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