Autrijus Tang wrote:
[..] For example, assuming argument types are unified in a single
phase, the example below does nothing useful:

    sub equitype ((::a) $x, (::a) $y) { ... }

It won't not help even if we replace the implicit "does" with "of":

    sub equitype ($x of (::a), $y of (::a)) { ... }

The reason, in Luke Palmer's words:

    "The trouble with this is that it doesn't provide any type safety.
     In the case of a type conflict, "a" just degenerates to the Any type."
     (cf. pugs/docs/notes/recursive_polymorphism_and_type)

Luke's analysis is indeed correct. And describes what can be inferred
from the caller side. And I wouldn't introduce the subtlety that the
first ::a is bound to the exact type of $x in the call environment, while
the second is a constraint on $y's type. But I would prescribe exactly
this as the meaning if you use plain 'a' as the type of $y. Thus I opt

   sub equitype ( ::a $x, a $y) { ... }

which is the same behaviour as for the value of $x which can be used
immediately for subsequent parameter bindings. Hmm, how do coderefs behave
in that respect?

   sub codeparam ( &foo, ?$val = foo ) {...}

Does this invoke a &bar argument once for the call codeparam( &bar )
and capture the result in $codeparam::val while the call
codeparam( &bar, 42 ) stores 42 without invoking &bar through
&codeparam::foo? And in which exact environment does a call to
&bar take place when needed to bind $val? Purely ::CALLER? Signature
as bound so far? ::OUTER of the use'er of the package which contains
&codeparam? Or the ::OUTER of the 'real' package file?

The other remark I have for the form with double ::a is that there's
also an inside view of that type. All type information inferred can
be stored as constraints on ::equitype::a in the ::equitype Code class.
Interesting is how the syntax for a more explicit form reads:

   sub equitype( ::a $x, ::a $y ) where { a.does(SomeRole) }

This fact, coupled with the unappealing (::a) syntax,

I like the syntax. BTW, does it have to have parens?
I would actually promote :: to a very fundamental operator/token.
Even if that costs some parens for the ternary ( ?? :: ).

leads me to look
for a more Perlish representation.  Adopting an idea from Odersky's
"Nested Types" paper, we can let terms occur at type variant position,
by introducing a "ref" form for types:

    sub equitype ($x, $y of ref($x)) { ... }
    sub subtype  ($x, $y does ref($x)) { ... }
    sub identity ($x) returns ref($x) { ... }

Uhh, please make that sig read ($x, type($x) $y) or at least
($x, $y.does($x.type) or something else with 'type' in it.
Ref is way to overloaded with meanings in Perl6 which are not
easy to unify away because of mismatches on the levels of
abstraction involved. E.g. the sub identity looks like an
alias for \ which it isn't from the type perspective.

This reads like Perl, and can be guarded with trivial compile time
and runtime checks.  We can also use type selectors to check
that &pick can always return Int from an Array[of => Int]:

    sub pick (@x) returns ref(@x).of { ... }

The only problem I can find is that the possible confusion between the
ref() operator and the unboxed basic type "ref".  Another thought is to
simply use ::() as a special "ref" form:

    sub pick (@x) returns ::(@x).of { ... }

But that can confuse with the symbolic dereference syntax.  All in all

Uhh, could we agree to call ::(symbolic) the symbolic lookup form and
::bareword the bareword, pre-runtime lookup form?
Let's not add another referencial thing to the 'Many Refs of Perl6'.
In the end we'll need a dedicated reference manual :)
I guess it would be S08.

Since I opt for ::pick beeing the innermost namespace immediately
after its introduction with 'sub pick' ::x could refer to @x from
the signature. Note that if there are &x, $x, @x and %x in the
signature a simple ::x is typed as their supertype Object.
Disambiguation would go as ::x::Code, ::x::Item, ::x::Array and
::x::Hash respectively. And of course you can further descent into
these namespaces as in pick::x::Array::of. Descending along multiple
pathes essentially means any'ing the types together ::x::*::of.
Well, in some namespaces things are all'ed together :)
The supertype of all array entries is of course pick::x::Array::values::*
and single items show up numerically under pick::x::Array::values::
e.g. pick::x::Array::values::8. Note that this is *not* a symbolic
form but well defined. It might evaluate to undef though.

Finally the .of method might just be syntactic sugar for the above:

   sub pick( @x ) returns @x.of {...}

or just

   sub pick( @x ) returns x.of {...}


   sub pick( @x ) returns x::of {...}

I'm more happy with ref(), but better suggestions welcome.

I suggest type(), tie() or soul()---the latter is from
'.bless() my .soul()'---if none of the above pleases @Larry.
$TSa.greeting := "HaloO"; # mind the echo!

Reply via email to