Re: Generic Parameter Proposal

2008-04-17 Thread John M. Dlugosz

TSa Thomas.Sandlass-at-barco.com |Perl 6| wrote:


Which is no problem if ::T defines it in the lexical scope. Any
outer definition is hidden. I guess re-using ::T in the same scope
again for capturing a new type is an error. Just like redeclaring
a value variable. BTW is
You appear to be saying that any use of Type with the sigil ::Type, in a 
signature where a type is expected, makes it generic and declares it 
hiding any outer value.


Reading S02 again, I see that is explained.
"C<::> can serve as its own sigil indicating intentional use of a 
not-yet-declared package name."


But the synopses uses ::Type to empasize that it is a Type, e.g. "$spot 
is initialized with ::Dog".


In one case it is used for a Signature.

  my ::MySig ::= :(Int, Num, Complex, Status)



And here it is used to indicate "type" so as not to run into reserved 
syntax:


Foo::<::Bar><::Baz> # same as Foo::Bar::Baz

And in S03:

Type names

   Num
   ::Some::Package


Class-qualified method call

   $obj.::Class::meth

In S06:

   is ::Foo[...]   # definitely a parameterized typename

In S10:

Since there are no barewords in Perl 6, package names must be predeclared,
or use the sigil-like C<::PackageName> syntax.  The C<::> prefix does not



imply top-levelness as it does in Perl 5.  (Use C<::*> for that.)




   $obj.Class::meth# same thing, assuming Class is predeclared


Finally, in S12:

In an rvalue context the C<::> prefix is a no-op, but in a declarational 
context, it binds a new type name within its declared scope.

===

So, I agree with your reading.  But I don't like it.  


--John





Re: Generic Parameter Proposal

2008-04-17 Thread TSa

HaloO,

John M. Dlugosz wrote:

First, consider the stated examples for Generic type parameters, from
the passage which defines the terminology in S02:


I fear we need a rigorous definition of generic first.


sub max (Num ::X @array)

> {
>push @array, X.new();
> }

Here you have a nice example of the variance problem.
Assuming Num <: Any the question is if push is callable
with Array[Num]. If Array[::T] is invariant on ::T
push has to have exactly this type. This is easily achievable
if push is itself parametric and the above instanciates
push[Array of X, X [EMAIL PROTECTED] on the fly.



Question 1 - can the Any be left off?  That is, ::X as an undeclared
type name used as the only type, syntactically correct?


Any can be dropped. But note that ::X captures the *actual*
type of @array. That is

  my Num @a = (1,2,3); # actually Array of Int
  my Num @b = (1.2, 2.2); # actually Array of Num

  compare( @a, @b ); # type error


Question 2 - is $x constrained to ::T or does that just note what it
was originally? (in cases where $x is not read only.  In this example
that is moot.)


It captures the actual type. To put a contraint on $x you need to
evaluate the type, that is use it without the :: sigil. For rw
parameters we can't allow variance if we want type safety anyway.
BTW, I wonder if the trait 'is ref' means write-only parameter?



So, we might want to capture that concrete type to, and write

Document Storable Positional ::DocType $doc;


Fine.


Now the fact that this is a generic type notwithstanding, it is just
another type in the list.  It just happens to be the same type that
is the actual type $doc was initialized with.  But, it implies that
yes, $doc is constrained to that type from then on.  The generic type
just customizes the list at run-time, but it is still a list of
juxaposed types, so they are ANDed together.


No.


Now we have a list of juxaposed type names, that are ANDed together.
The generic type is the one that wasn't defined (as a type) before.
It needs the :: so it doesn't flag as an undefined symbol, but the
others could have the sigil if you wanted to be explicit:

::Document ::Storable ::Positional ::DocType $doc;


Hopefully not. This just captures the type $doc into four variables.



::T $x;


No, this is just like &foo is different from foo. It does not
constrain $x to T but captures Any in this case. And if T is already
declared in this scope it's a redeclaration error. S02 seems to say
that this just rebinds ::T but that means to loose it as a unique
type parameter for the scope! So we should change that.

BTW, C# raises an error for the following case

  sub foo ($a)
  {
  my $x = 3;

  if $a > 0
  {
 say $x; # error usage before declaration

 my $x = 17; # in effect from start of scope

 say $x;
  }
  }

and I see some merit in it. How is Perl 6 supposed to handle this?



That answers the two questions, based only on other things in the
Synopses.


Ups, my reading is different.




Now for a proposal, and the observation of an issue.

The only thing that makes a generic type parameter generic is that it
was previous undefined as a type.  So, what if you have code that's
working just fine, and then some other change puts a symbol T into
the lexical scope, perhaps as a global import?  Boom!  The code
changes meaning drastically.


Which is no problem if ::T defines it in the lexical scope. Any
outer definition is hidden. I guess re-using ::T in the same scope
again for capturing a new type is an error. Just like redeclaring
a value variable. BTW is

sub foo ($x)
{
   my $x; # redeclaration error?
}

just funnily hiding the parameter $x or an error?



Contrast that to the normal meaning of declaring a variable, in which
case it hides anything with the same name in the outer scopes.
Introducing a global one does not change the code that uses lexical
variables.  Except for generics.  That is inconsistant and wrong for
the same reason that it would be wrong for all other kinds of
symbols.


Which is why it isn't so, or is it? Please correct me if I'm wrong!



To address this, I propose using a positive way to declare generic
parameters rather than having them implicit based on not previously
existing.  I propose the triple colon, :::, for this purpose:

:::T $x;


Which is ugly.


Regards, TSa.
--

"The unavoidable price of reliability is simplicity"
  -- C.A.R. Hoare


Generic Parameter Proposal

2008-04-16 Thread John M. Dlugosz
First, consider the stated examples for Generic type parameters, from the 
passage which defines the terminology in S02:

sub max (Num ::X @array) {
push @array, X.new();
}

sub compare (Any ::T $x, T $y) {
return $x eqv $y;
}

There are only two paragraphs and these two examples, so many questions are 
"begged".  I propose to answer many of these with this treatment, and hold it 
up for peer review and acceptance.  I also want to propose a new feature change.

Question 1 - can the Any be left off?  That is, ::X as an undeclared type name 
used as the only type, syntactically correct?

Question 2 - is $x constrained to ::T or does that just note what it was 
originally? (in cases where $x is not read only.  In this example that is moot.)

The syntax to define the value type for variables provides for multiple types 
simply listed one after the other, which are taken to mean "and".

Dog Fish $x;

This means that $x must have both Dog and Fish interfaces.  A better example 
might be

Document Storable Positional $doc;

where the code makes use of several different fairly abstract interfaces and 
doesn't care what kind of concrete class it gets.

So, we might want to capture that concrete type to, and write

Document Storable Positional ::DocType $doc;

Now the fact that this is a generic type notwithstanding, it is just another 
type in the list.  It just happens to be the same type that is the actual type 
$doc was initialized with.  But, it implies that yes, $doc is constrained to 
that type from then on.  The generic type just customizes the list at run-time, 
but it is still a list of juxaposed types, so they are ANDed together.

Mammel Elephant $dumbo;

might be redundant if Elephant .does Mammel.  But that's beside the point.  
Likewise that DocType (after binding) subsumes all the others in the list.

Now we have a list of juxaposed type names, that are ANDed together.  The 
generic type is the one that wasn't defined (as a type) before.  It needs the 
:: so it doesn't flag as an undefined symbol, but the others could have the 
sigil if you wanted to be explicit:

::Document ::Storable ::Positional ::DocType $doc;

Whether or not the sigil was present is lost on the semantic meaning, once it 
gets past the parser.  The only reason we had it on ::DocType or ::T was 
because it was not defined.

The only real difference between the generic type and the others is that one 
was not previously known.  Really, it is just a list of type names.

So,

::T $x;

Should be just fine.  The parser is not depending on another type already seen 
before that.  It is a list of one type, and after it figures that out, it later 
notices that it is not defined yet.

That answers the two questions, based only on other things in the Synopses.

Now for a proposal, and the observation of an issue.

The only thing that makes a generic type parameter generic is that it was 
previous undefined as a type.  So, what if you have code that's working just 
fine, and then some other change puts a symbol T into the lexical scope, 
perhaps as a global import?  Boom!  The code changes meaning drastically.

Contrast that to the normal meaning of declaring a variable, in which case it 
hides anything with the same name in the outer scopes.  Introducing a global 
one does not change the code that uses lexical variables.  Except for generics. 
 That is inconsistant and wrong for the same reason that it would be wrong for 
all other kinds of symbols.

To address this, I propose using a positive way to declare generic parameters 
rather than having them implicit based on not previously existing.  I propose 
the triple colon, :::, for this purpose:

:::T $x;

I beleive this does not conflict with anything, and it is in the same spirit as 
@@ and ;;.

--John