Re: The meaning of returns

2005-07-28 Thread TSa (Thomas Sandlaß)

HaloO Autrijus,

you wrote:

 D) Make the return type observe both #2 and #3 at compile time,
using type variables:

   sub id ( (::T) $x ) returns ::T { return($x) }



And this is a natural extension to guide the inferencer so it won't be
totally giving up on polymorphic functions such as id.  C) and D) can
be taken together, resulting to a powerful soft typed language.


This is my preference. The only known issue with parametric typing is
the proliferation of params as soon as you want to stay away from
unpecificity.



However, if we take the view that type annotation are merely storage
allocation hints and runtime coercers, then A) is probably the way to go.


Please no. Or at least not exclusively. I see your storage allocation
hints as a data environment needed to implement the type.
--
$TSa.greeting := HaloO; # mind the echo!


The meaning of returns

2005-07-27 Thread Autrijus Tang
Consider this:

sub id (Any $x) returns Any { return($x) }
sub length (Str $y) returns Int { ... }

length(id(abc));

Under standard static subtyping rules, this call will perform three
different typechecks:

 1) abc.does(Any) # (abc as Str)  === (Any $x) in id
 2) $x.does(Any)# ($x as Any) === (returns Any) in return
 3) Any.does(Str)   # (returns Any)   === (Str $y) in length

The final (returns Int) is unimportant here.

Obviously, typecheck #3 fails, as Any cannot do Str.  Indeed, there is
no type literal in the return position that can satisfy this static
typecheck for id, other than the bottom type which would be a subtype
for every type.  Let's call it All:

sub id (Any $x) returns All { return($x) }

However, had we used that, #2 will fail, as it would now be checking for
$x.does(All), which is guaranteed to fail regardless of whether the
check occurs at runtime (Str.does(All)) or compile time (Any.does(All)).

Hence, it seems to me that there are only four ways out:

  A) Omit the #3 check from compile time; at runtime, use the actual
 type of $x.  The returns type annotation will not propagate
 outward to the caller.
 
At compile time, check for #2: Any.does(Any)
At runtime, check for #2: abc.does(Any)
check for #3: abc.does(Str)

  B) Omit the #2 check from both compile time and runtime; this allows
 us to write the returns All version.
 
At compile time, check for #3: All.does(Str)
At runtime, check for #3: abc.does(Str)

  C) Make the return type observe both #2 and #3 at compile time,
 using junctive types to pass both checks:

sub id ( Any $x ) returns Any|All { return($x) }

  D) Make the return type observe both #2 and #3 at compile time,
 using type variables:

sub id ( (::T) $x ) returns ::T { return($x) }

At this moment, I don't have a strong preference to either; I'm more
curious on whether this topic has been covered before by p6l and @Larry.

Thanks,
/Autrijus/


pgpRRbY7g7rEe.pgp
Description: PGP signature


Re: The meaning of returns

2005-07-27 Thread Autrijus Tang
On Thu, Jul 28, 2005 at 05:03:05AM +0800, Autrijus Tang wrote:
 Hence, it seems to me that there are only four ways out:

Some annotations copied from discussion in #perl6:

   A) Omit the #3 check from compile time; at runtime, use the actual
  type of $x.  The returns type annotation will not propagate
  outward to the caller.
  
 At compile time, check for #2: Any.does(Any)
 At runtime, check for #2: abc.does(Any)
 check for #3: abc.does(Str)

This is the view that says (returns Foo) amounts to declare a:

my sub return (Foo $x) { *return($x) }

and perform no static checking for return types to match their calling
context.  It's got the dynamic language feel, which means practically
no nontrivial type errors will happen at compile time, because function
calls, regardless of its declared return type, can be used in any type
context.

   B) Omit the #2 check from both compile time and runtime; this allows
  us to write the returns All version.
  
 At compile time, check for #3: All.does(Str)
 At runtime, check for #3: abc.does(Str)

This is quite absurd, and was included only for completeness.

   C) Make the return type observe both #2 and #3 at compile time,
  using junctive types to pass both checks:
 
 sub id ( Any $x ) returns Any|All { return($x) }

This is similar to the approach taken by OO-style local type
inferencers; see the Colored local type inference paper for details.

The idea is that, if one omits the returns declaration from a function
of undecidable type, the inferencer can silently fill in (Any|All) and
make the program compile, effectively defer typechecks to runtime.

On the other hand, if the user does provide a type annotation, then both
#2 and #3 will be observed, and type errors can occur.  It's closer to
the soft typing or incremental typing idea.

   D) Make the return type observe both #2 and #3 at compile time,
  using type variables:
 
 sub id ( (::T) $x ) returns ::T { return($x) }

And this is a natural extension to guide the inferencer so it won't be
totally giving up on polymorphic functions such as id.  C) and D) can
be taken together, resulting to a powerful soft typed language.

However, if we take the view that type annotation are merely storage
allocation hints and runtime coercers, then A) is probably the way to go.

Thanks,
/Autrijus/


pgpcVsbqfgSlq.pgp
Description: PGP signature


Re: The meaning of returns

2005-07-27 Thread Autrijus Tang
On Thu, Jul 28, 2005 at 05:57:28AM +0800, Autrijus Tang wrote:
 On Thu, Jul 28, 2005 at 05:03:05AM +0800, Autrijus Tang wrote:
  Hence, it seems to me that there are only four ways out:
 
 Some annotations copied from discussion in #perl6:

Last time I reply to myself on this thread, hopefully. :-)

B) Omit the #2 check from both compile time and runtime; this allows
   us to write the returns All version.
   
  At compile time, check for #3: All.does(Str)
  At runtime, check for #3: abc.does(Str)
 
 This is quite absurd, and was included only for completeness.

On second thought, this is not as absurd as it seems.  This view is that
sub f () returns Foo means f() can be used in any place that a Foo
literal can occur, which means that it can be used in contexts that
demands a supertype of Foo (like Any), but never a subtype of Foo.

The language defined this way would still be dynamic; disabling #2 means
that the type of $x will not be checked against Foo upon return($x), so
anything at all can be used in that position.  Meaningful type errors
can occur, for example when saying close(length(abc)), where length
would have returns Int and close have a IO parameter.

However, this does require the curious device of returns All as the
default return type, unless we eliminate that using type variables
and/or type inferencing, at which time we can get #2 back for free and
implement full static typechecking anyway.

Thanks,
/Autrius/


pgpaH5X3qHeTw.pgp
Description: PGP signature