Re: sub foo ($x) returns ref($x)
HaloO, 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 for: 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 {...} or 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!
Re: sub foo ($x) returns ref($x)
On Mon, Aug 01, 2005 at 03:16:50PM +0200, TSa (Thomas Sandla�) wrote: sub equitype ( ::a $x, a $y) { ... } That's not a bad idea at all. I rather like it. I'd just still like an explicit type-unifying parens around ::a, just so people won't say sub foo (::Int $x) { ... } and accidentally rebind Int. 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? Yes. 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 lexical scope of the sub, with the signature bound so far. Thanks, /Autrijus/ pgpM1FYbFZk1F.pgp Description: PGP signature
Re: sub foo ($x) returns ref($x)
HaloO, Autrijus Tang wrote: On Mon, Aug 01, 2005 at 03:16:50PM +0200, TSa (Thomas Sandla�) wrote: sub equitype ( ::a $x, a $y) { ... } That's not a bad idea at all. I rather like it. I'd just still like an explicit type-unifying parens around ::a, just so people won't say I try to maintain the 'parens only group' point of view. But it seems to be violated elsewhere, too. sub foo (::Int $x) { ... } and accidentally rebind Int. Why so shy? It would rebind foo::Int with respect to the inside of foo. Of course the funny effect is that for a call foo( blahh ) foo::Int means Str :) I guess this is why $Larry wants a role wrapped around such type parameter instanciators: role Foo[::Int] # hides *Int { sub foo (Int $x) { ... } } and explicit instanciation use Foo[Int]; # or some such use Foo[Str]; use Foo[Num]; But I don't know if he also wants to carry that on to the actual calls: Foo[Int]::foo(42); Foo[Str]::foo('42'); Foo[Num]::foo(3.14); OTOH, one has to use *::Int or *Int to surely get the standard Int, anyway. And for getting guaranteed type locality inside foo a sub foo( MY::Int $x ) {...} might be needed, too. This nicely fits other pseudo namespaces: sub foo( Int $x ) {...} # whatever Int is in effect # at compile time sub foo(::Int $x ) {...} # deferred lookup to CHECK time sub foo( MY::Int $x ) {...} # dynamically from $x sub foo( foo::Int $x ) {...} # same for all invocations? error? sub foo( OUR::Int $x ) {...} # from package How usefull OUTER::, CALLER::, etc. are I have no idea. Perhaps it's a good idea to reserve single capital letter barewords for type params. Or a twigil if we think of '::' beeing s sigil: sub foo( ::^a $x ) {...} This saves one character compared to your (::a) which is the same length as MY::a. -- $TSa.greeting := HaloO; # mind the echo!
sub foo ($x) returns ref($x)
Suppose we have a function that takes an argument and returns something with the same type as that argument. One previous suggestion is this: sub identity ((::a) $x) returns ::a { return(...) } This is fine if both invariants in the the meaning of 'returns' thread are observed, since the inner return will check that (...).does(::a), and the outer context will demand ::a.does(ref($x)). However, this relies on the fact that we unify argument types first, then use the bounded type variables to handle returns types. Under that scheme, It is less clear how to talk about how the types of two arguments must relate. 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) This fact, coupled with the unappealing (::a) syntax, 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) { ... } 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 I'm more happy with ref(), but better suggestions welcome. Thanks, /Autrijus/ pgptLqlFfMjT8.pgp Description: PGP signature