Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-31 Thread Michael Zedeler.

On 2014-03-29 21:45, Damian Conway wrote:

Moritz wrote:

To spin the tale further, we need to think about what happens if
somebody writes

multi foo(1|2e0) { ... }

so now we have Int|Num. We could explore the most-derived common
ancestor (Cool), or look into role space (Real, Numeric come to mind),
or simply error out.

Or maybe we need to reconsider the whole idea that it's appropriate to
infer type from a smartmatched constraint?

[...]

In other words specifying a constraint value is a way of applying a
smartmatched acceptance test to a parameter, but the type of the
acceptance test is typically totally unrelated to the type of the
parameter.

Which is why it now seems very odd to me that we are currently inferring
parameter types from constraint values.
I couldn't agree more. This looks like a piece of odd-sized baggage left 
behind by Moose, where declaring type constraints on attributes is too 
easily mistaken as actual type declarations.


Other languages may provide simple restriction rules for parameter value 
domains in the shape of types, but in a dynamically typed language, it 
doesn't make much sense, since there may be conversion paths between the 
types involved.


I'd much more prefer a pure matching language where no assumptions about 
types are done automatically, forcing me to write explicit type 
constraints myself, if I believe they are necessary (they should rarely 
be needed, since having to deal too much with types in a dynamically 
typed language is counterproductive :-) ).


In general - Perl (5) is a great tool because it doesn't force people to 
deal too much with typing (both implicit and explicit). Lets keep it 
that way.

--
Michael Zedeler
70 25 19 99
mich...@zedeler.dk mailto:mich...@zedeler.dk

dk.linkedin.com/in/mzedeler http://dk.linkedin.com/in/mzedeler/ | 
twitter.com/mzedeler https://twitter.com/mzedeler | 
github.com/mzedeler https://github.com/mzedeler/


Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-31 Thread Michael Zedeler.

On 2014-03-31 14:49, Michael Zedeler. wrote:

On 2014-03-29 21:45, Damian Conway wrote:

Moritz wrote:

To spin the tale further, we need to think about what happens if
somebody writes

multi foo(1|2e0) { ... }

so now we have Int|Num. We could explore the most-derived common
ancestor (Cool), or look into role space (Real, Numeric come to mind),
or simply error out.

Or maybe we need to reconsider the whole idea that it's appropriate to
infer type from a smartmatched constraint?

[...]

In other words specifying a constraint value is a way of applying a
smartmatched acceptance test to a parameter, but the type of the
acceptance test is typically totally unrelated to the type of the
parameter.

Which is why it now seems very odd to me that we are currently inferring
parameter types from constraint values.
I couldn't agree more. This looks like a piece of odd-sized baggage 
left behind by Moose, where declaring type constraints on attributes 
is too easily mistaken as actual type declarations.
Sorry - correction: where declaring type constraints should be where 
declaring value constraints.

--
Michael Zedeler
70 25 19 99
mich...@zedeler.dk mailto:mich...@zedeler.dk

dk.linkedin.com/in/mzedeler http://dk.linkedin.com/in/mzedeler/ | 
twitter.com/mzedeler https://twitter.com/mzedeler | 
github.com/mzedeler https://github.com/mzedeler/


Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-29 Thread Damian Conway
Moritz wrote:

 To spin the tale further, we need to think about what happens if
 somebody writes

 multi foo(1|2e0) { ... }

 so now we have Int|Num. We could explore the most-derived common
 ancestor (Cool), or look into role space (Real, Numeric come to mind),
 or simply error out.

Or maybe we need to reconsider the whole idea that it's appropriate to
infer type from a smartmatched constraint?

Because, having pondered it at some length, I think we could very
reasonably decide that, when providing a constraint, the coder is not
making any reliable implication regarding the associated parameter type.

Let's look at some examples...

1. Suppose we wanted a subroutine that classifies numbers according to a
   very simple scheme.  We might write:

multi classify($ where 0   ) { 'zero' }
multi classify($ where 1..9) { 'digit'}
multi classify($   ) { 'sequence' }

   It would be more convenient if we could just write:

multi classify( 0) { 'zero' }
multi classify( 1..9 ) { 'digit'}
multi classify( $) { 'sequence' }

But we can't, because the current inference rules would infer:

multi classify(Int   $ where 0   ) { 'zero' }
multi classify(List[Int] $ where 1..9) { 'digit'}
multi classify(Any   $ where *   ) { 'sequence' }

which is not helpful. It goes wrong because, except in the first
version of Cclassify, the type of the parameter constraint does
not imply the type of parameter.


2. Or suppose we wanted a subroutine that only ever accepts a given
   argument once. We might write:

sub unseen ($msg) { state %seen; %seen{$msg}++; }

multi ping($ where unseen ) { die 'One ping only!' }
multi ping($msg) { say PING! ($msg)   }

   It would be more convenient if we could write:

multi ping({.unseen}) { die 'One ping only!' }
multi ping($msg  ) { say PING! ($msg)   }

But we can't, because the current inference rules would make that:

multi ping(Block $ where {.unseen}) { die 'One ping only!' }

which is not helpful. Because, again, the type of the constraint
does not imply (nor is it even directly related to) the type of the
parameter.


3. Or suppose we wanted to detect special boundary conditions
   (a case similar to Moritz's example above). We might write:

multi check_value($ where 0|1e6) { fail 'edge case!' }
multi check_value($) { return True   }

   It would be more convenient if we could write:

multi check_value(0|1e6) { fail 'edge case!' }
multi check_value($) { return True   }

   But we can't, because the current inference rules would make that:

multi check_value(Junction $ where 0|1e6) { fail 'edge case!' }
multi check_value( $) { return True   }

which is not helpful. Because, as before, the type of the constraint
is not correlated with the type of the parameter.


In each case (and in the majority of other cases, I suspect) the type
and the constraint value are performing two entirely distinct tasks,
and are often unrelated. Or, at least, unrelated in the sense that the
constraint value is frequently not type-compatible with the type,
because the constraint is verified by smartmatching, which is most often
an operation between values of two unrelated types: integer matched
against block, string matched against list, number matched against
junction, etc. etc.

In other words specifying a constraint value is a way of applying a
smartmatched acceptance test to a parameter, but the type of the
acceptance test is typically totally unrelated to the type of the
parameter.

Which is why it now seems very odd to me that we are currently inferring
parameter types from constraint values.

The type of the constraint value tells us nothing reliable about the
type of the parameter it constrains. It only tells us that the value of
that parameter must be matchable against the value of that constraint.

And that appears to be true even for the very simplest example:

sub foo($ where 1) { say 'There can be only one!' }

foo(1);  # Okay
foo('1');# Okay
foo(True);   # Okay
foo([42]);   # Okay
 # et cetera...

I ought to be able to write that as:

sub foo(1) { say 'There can be only one!' }

but I cannot, because the current rules don't even infer a
coercive type.


TL;DR: In general, the type of a parameter's Cwhere constraint value
   has little to do with the type of the parameter,
   because constraints are smartmatched, not type-matched.


My proposal, therefore, is that any parameter specified only as a
constraint value simply does not attempt to infer its parameter type at
all, but just retains its default type of Any.

That is, in all cases:

sub foo( SOME_VALUE ) {...}

is just a shorthand for:

sub foo($ where SOME_VALUE ) 

Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-28 Thread Moritz Lenz


On 03/28/2014 02:28 PM, Parrot Raiser wrote:
 On 3/27/14, Moritz Lenz mor...@faui2k3.org wrote:
 
 Agreed. We just need to come up with a consistent, intuitive way to
 handle the rest of the cases. And implement it.

 
 Whenever somebody offers a solution to a problem formulated as We
 just need to  (or why don't you just?), it's usually a sign
 that they've overlooked some fundamental aspect of the problem. Or, as
 I suspect in this case, poured irony all over it. :-)*

Sorry, it's not meant ironic at all. I just meant to indicate that
speccing without implementation is a useless exercise, and right now I'm
not seeing myself as the one who thinks through and decides on all the
corner cases, and implements it.

Cheers,
Moritz


Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-27 Thread Moritz Lenz


On 03/19/2014 11:06 AM, Damian Conway wrote:
 To me, the issue is: how does Perl 6 actually carry out the
 type inference we're doing here?
 
 And I believe it's an important question to get right, as we
 may eventually see Perl 6 doing more type inference...either
 in core, or else through some nefarious module that some
 evil genius eventually writes. ;-)
 
 If Perl 6 does type inference on some $value simply by calling
 $value.WHAT, then:
 
 multi foo(0|1) {...}
 
 should indeed be equivalent to:
 
 multi foo(Junction $ where 0|1) {...}
 
 
 However, that's not the only possibility (nor, in my opinion,
 the most predictable or useful).
 
 If, for example, Perl 6 did type inference by calling an internal:
 
 multi infer-type (Any $value) { $value.WHAT }
 
 then:
 
 multi foo(0|1) {...}
 
 would be equivalent to:
 
 multi foo(Int|Int $ where 0|1) {...}
 
 which is, of course, just:
 
 multi foo(Int $ where 0|1) {...}

No.

The type of Int|Int is still Junction, not Int.

However you turn the problem, you'll need some form of special-casing to
fold Int|Int into Int, and please formulate it so that the Mu case
continues to work.

To spin the tale further, we need to think about what happens if
somebody writes

multi foo(1|2e0) { ... }

so now we have Int|Num. We could explore the most-derived common
ancestor (Cool), or look into role space (Real, Numeric come to mind),
or simply error out.

 which, in my view, would be a much more useful outcome in the vast
 majority of cases.

Agreed. We just need to come up with a consistent, intuitive way to
handle the rest of the cases. And implement it.

Cheers,
Moritz

 I accept that it's important to be able to explicitly declare a
 parameter as a Junction, so it's immune to junctive autothreading,
 but I don't think that should be the norm...and certainly shouldn't
 happen implicitly. That's why variables, parameters, and return values
 that are not explicitly typed default to Any, rather than to Junction.
 
 And, I think this is another implicit case where a non-junctive outcome
 would be more useful...and more widely expected.
 
 In other words, for the one time in a thousand (or fewer) where I
 actually want:
 
 sub foo(Junction $ where 0|1) {...}
 
 then I should have to be explicit about that argument being junctive
 (because I should *always* have to be explicit about an argument being
 junctive).
 
 And for the 999 times I want:
 
 sub foo(Any $ where 0|1) {...}
 
 I should be able to just write:
 
 sub foo(0|1) {...}
 
 
 Damian
 


Re: [perl #121454] Can't inline complex constraints in multisub signatures

2014-03-19 Thread Moritz Lenz
f'up to p6l, because the ticket doesn't need the rest of the discussion.

On 03/19/2014 10:21 PM, Darren Duncan wrote:
 On 2014-03-19, 1:20 AM, Moritz Lenz wrote:
 On 03/19/2014 12:45 AM, Darren Duncan wrote:
 Damian, Moritz, etc,

 It seems to me that the basic problem here is that the vertical bar |
 has 2 different meanings (outside rules) depending on context.

 When used with type names it produces a union type, while with normal
 values such as integer literals it produces a junction value.

 No. It's always a Junction. Perl 6 has no union types.
 
 Really?  All this time I thought in Perl 6 you could write say:
 
my Int|Str $foo;

You were wrong.

The only way to achieve something comparble is

subset IntStr of Any where Int|Str

but for example for multi dispatch, it matters that not a nominal type
matched, but rather a constraint, so that's a not a great replacement.

 Or otherwise say Int|Str anywhere a type name could go, and then this is 
 saying 
 you accept anything that is a Int or a Str but nothing else there.
 
 Was that never true or was it replaced by something while I wasn't looking?

There was something like that in the specs, but no concept whatsoever of
how that might work. You can't just slap on union types onto an existing
type system, and have it magically work out. In languages like Haskell
where they work fine, they are right at the core of the language.

So the feature was removed years ago, because it's not really implementable.

Cheers,
Moritz