Re: Type variables vs type literals

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

HaloO Larry,

you wrote:

: Could you explain what exactly 'run-time lazy type aliasing' is?
: I mean what does it achieve and how does it compare to type
: instanciation and parametric contraint checking?

It achieves guaranteed *late* binding of types, whereas generics/roles
are biased towards early binding (class composition time, usually at
compile time).


To me binding implies prior existance. That is the type instanciation
takes place elsewhere and flows into a scope as a temporarily bound
variable. How do you intent to achieve demand driven on-the-fly type
instanciations? This seems to me a necessity for Perl6 where not all
type information is available at compile time.




: Something like unary operator does?

Don't follow that.


Well, I regard operator does as binary. It's LHS is the receiver of the
role given as the RHS. This composing into comes in two modes for
compile time and runtime. E.g.

class LHS does RHS {...}  # binary does at compile time

$x does RHS; # runtime role attachment

does RHS;# unary form?



: The only thing I did was to replace the :: sigil with a subtype
: declaration.

It's the lack of a my that bothers me.

: Does subtype always go into global scope? I thought
: that it requires a *name to go into global and our to go to the
: innermost module---or was that package?

For unqualified packages/modules/classes the default up till now has
been to put them into *.  But I think I'm going to change that.  See below.


That is very wise. But I would make a distinction in defaulting to
my or our: the keyword declared things like class, sub, etc default
to our, while the sigiled variables default to my. The latter would
prevent data leakage and auto-vivification surprises:

sub a { $x = 'a' }
sub b { $x = 'b' }

sub x
{
   rand()  0.5 ?? a :: b;
   say $x; # should print undef unless $x defined before a
}



: I mean even non-declared
: auto-vivified vars go into the immediately surrounding scope,
: or am I horribly mistaken?

They are our by default, not my.  Just as subs are our by
default.  And indeed, that is probably what package/module/class
names are going to default to as well.


I think that forcing our on variables that shall go to the outer
scope where sharing is intended is a good idea. There could even be
a compiler mode that doesn't actually produce bytecode but re-writes
the source with nested our declaration moved to there proper place.

The purpose of my and our declarations is to give the compiler
and the runtime environment about the declared variable. Our stores
that information at the innermost level of collaboration while my
stores it at the innermost scope. For auto-vivified vars no storing
is needed because they bear no specific meaning.



 I was confused because I
thought of file-scoped class Foo; declarations as defaulting directly
to *.  That's inaccurate.  It's just that the current package at the
start of a file happens to be *, and so it doesn't matter if you
say class Foo or our class Foo, because they mean the same thing
at that point.  If you say class Bar within the scope of any other
package/module/class, though, it should default to our class Bar.
So it might as well default to our everywhere.  The upshot is that
if you want to declare a module that declares a bunch of global classes
inside it, you have to use *.  That seems like good documentation anyway.
Only the first class or module declaration in a file defaults to *.


I think it defaults to the scope it is embedded into. Conceptually
a module is instanciated into the surrounding scope by a use statement.
The implementation might of course be optimised in loading the generic
code of the module ones and create a proxy and/or specific instanciations
of generics into the importing scope.



Hmm.  Does that mean that the top-level program starts running in *
instead of in Main.  Or maybe the * rule only works on .pm files?


I would keep files out of the picture. The canonical form of a
Perl6 program is the concatination of all sources with the
package Foo; ... eof replaced with package Foo {...}.

In this line of thinking * is the outer shell of the Perl6 bubble
you are in. Immediately outside that bubble one typically finds
Parrot or Pugs, but it could be other forms of programatical
embedding.



: my ::TypeRef; # type variable?

No, that's what I've been trying to say.  I haven't wanted ::T to be a type
variable by itself.  It's a type literal that simply doesn't have to
have been declared yet, but we know that if it had been declared, we
could also call it bare T.  I want some other syntax for declaring
type variables that involves explicitly mying or ouring the type.
[Or at least I did want it.  I change my mind below.]

So currently the above would be a syntax error.  We don't want
::TypeRef to behave differently in

my ::T;
my ::T $foo;

They should either both declare ::T, or both refer to an existing
type literally named T.  That's where the ::-as-a-variable-sigil

Re: Type variables vs type literals

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

HaloO Larry,

you wrote:

Well, there's something to be said for that, but my gut feeling says
that we should reserve the explicit generic notation for compile time
processing via roles, and then think of run-time lazy type aliasing


Could you explain what exactly 'run-time lazy type aliasing' is?
I mean what does it achieve and how does it compare to type
instanciation and parametric contraint checking?



as something a little different.  So if you really want to write
that sort of thing, I'd rather generalize roles to work as modules
containing generic subs:

role FooStuff[T] {
sub foo (T $x, T $y) { }
...
}

Otherwise people are tempted to scatter generics all over the
place, and it's probably better to encourage them to group similarly
parameterized generics in the same spot for sanity.  It also encourages
people to instantiate their generics in one spot even if they're
calling them from all over.

[..]

I think people should say does FooStuff[Int] and automatically alias
all the routines to the Int form so we don't have to scatter :[Int]
all over.  Or if they just say does FooStuff, they get lazily-bound
type parameters.


I get that right, FooStuff can be instanciated without a class or object?
Something like unary operator does? Into which scope do these role 
instanciations go? Does does *FooStuff[Int] mean global?




: ::T $x := $obj;
: my T $y = $x;
: 
: The prime use of that feature is to ensure type homogenity for

: temporary and loop vars in a certain scope. But the scope in the
: above syntax is not apparent enough---to me at least.

Actually, I was holding those up as bad examples of scope visibility,
so I'm agreeing with you there.  (Which is why I suggested that we
require a my context, even if only implied by the formal paramter list.)

: Thus I opt for an explicit
: 
:subtype T of $obj.type; # or just $obj perhaps?

:T $x := $obj;
:my T $y = $x;

Yuck.  I think that completely obscures the lazy type binding.
Plus you've managed to omit the my, so you've created a global
subtype T.  (Unless, as I'm leaning towards, we make such bare inner
types illegal, and require my, our, or *.)


The only thing I did was to replace the :: sigil with a subtype
declaration. Does subtype always go into global scope? I thought
that it requires a *name to go into global and our to go to the
innermost module---or was that package? I mean even non-declared
auto-vivified vars go into the immediately surrounding scope,
or am I horribly mistaken?

sub foo()
{
   if (1) { $x = 'from above' }
   if (2) { say $x }  # prints 'from above' even if no outer $x exists?

   say $x; # prints undef or 'from above' if outer $x
}


Up til now I assumed that ::T and plain T mean exactly the same if T
is pre-declared/defined. The type sigil is only needed to defer the
definition/binding. In a certain sense this is a hanging type reference
similar to foo beeing a reference to Code. Which brings me to the
question how to bind a type reference. I mean we have

my fooref := foo

which allows fooref() calls, right? How are type references derefed
if not by dropping the sigil? ::TypeRef() perhaps?

my ::TypeRef; # type variable?

sub make ( ::Type, Type $value ) returns Type
{
   if (::TypeRef != ::Type)
   {
  ::TypeRef = ::Type;
   }
   my Type $x;
   $x = $value;
   return $x;
}

my $i = make(Int, 17);
my @a = make(Array, [1,2,3]); # single element array?
  # or three element array?

my $e = make(Int 'string'); # type error in make?

With the automatic binding of a ::Type variable to the type
of it's argument the definition of make could be shortend to

sub make ( ::Type $value ) returns Type
{ ... }

and called like this

my $i = make(17);

which at least prevents type errors ;)


Regards,
--
TSa (Thomas Sandlaß)




Re: Type variables vs type literals

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

HaloO Larry,

you wrote:

On Thu, Jun 30, 2005 at 09:25:10AM +0800, Autrijus Tang wrote:
: Currently, does this:
: 
: sub foo (::T $x, ::T $y) { }
: 
: and this:
: 
: sub foo (T $x, T $y) { }
: 
: Means the same thing, namely
: 
:a) if the package T is defined in scope, use that as the

:   type constraint for $x and $y
: 
:b) otherwise, set ::T to be the most immediate common supertype

:   of $x and $y.
: 
: Is this understanding correct?  I'd like to disambiguate the two cases

: by making ::T in parameter list to always mean type variable (sense b),
: and the bare T always mean type name (sense a)?

I think it would be good to distinguish those, but I've been mulling
over whether ::T should be the syntax for b.  (And also whether b
is the correct way to think about it in Perl 6.)  The problem with
using ::T for autovivify your type from the argument is that ::($x)
doesn't mean that, and it looks like it should.


I think the point is that using a type variable in the signature of a sub
is too subtle for recognizing it as a type function that produces typed
subs. Thus---even if it resembles C++ templates---I suggest to put the
type parameters onto the sub:

sub foo[T] (T $x, T $y) { }

which basically constrains $x and $y to have the same type. A call
to foo might automatically instanciate appropriate implementations.
With MMD and all methods and attributes beeing virtual this could
usually be a no-op as far as the code generation is concerned.
But the type checker has to know what constraints are in effect.


The syntax for explicit selection could be foo:(Int)('3','2') which
prevents the interpretation foo:(Str,Str). OTOH, this might overload
the :() too much. Could we invent more colon postfix ops?
Thus the above were foo:[Int]('3','2'). And while we are at it
since () is more call-like and [] lookup-like we could reserve :()
for more complicated type literals and use :[] for formal type signatures
on subs as it is the case for roles.



 The :: does imply
indirection of some sort in either case, but it's two very different
kinds of indirection.  ::($x) can't declare a lexical alias for
some type, whereas ::T presumably could, though your formulation seems
more of a unificational approach that would require ::T everywhere.

In other words, if we do type binding like b, we would probably want to
generalize it to other binding (and assigning?) contexts to represent
the type of the bound or assigned object, and at the same time create
a lexical alias for the bare type.  So we might want to be able to say

::T $x := $obj;
my T $y = $x;


The prime use of that feature is to ensure type homogenity for
temporary and loop vars in a certain scope. But the scope in the
above syntax is not apparent enough---to me at least.
Thus I opt for an explicit

   subtype T of $obj.type; # or just $obj perhaps?
   T $x := $obj;
   my T $y = $x;

With my proposal from above the short form could be

   :[T] $x := $obj;
   my T $y = $x;

or the current form with :()

   :(T) $x := $obj;
   my T $y = $x;


Regards,
--
TSa (Thomas Sandlaß)




Re: Type variables vs type literals

2005-07-04 Thread Larry Wall
On Mon, Jul 04, 2005 at 04:09:59PM +0200, TSa (Thomas Sandlaß) wrote:
: I think the point is that using a type variable in the signature of a sub
: is too subtle for recognizing it as a type function that produces typed
: subs. Thus---even if it resembles C++ templates---I suggest to put the
: type parameters onto the sub:
: 
: sub foo[T] (T $x, T $y) { }
: 
: which basically constrains $x and $y to have the same type. A call
: to foo might automatically instanciate appropriate implementations.
: With MMD and all methods and attributes beeing virtual this could
: usually be a no-op as far as the code generation is concerned.
: But the type checker has to know what constraints are in effect.

Well, there's something to be said for that, but my gut feeling says
that we should reserve the explicit generic notation for compile time
processing via roles, and then think of run-time lazy type aliasing
as something a little different.  So if you really want to write
that sort of thing, I'd rather generalize roles to work as modules
containing generic subs:

role FooStuff[T] {
sub foo (T $x, T $y) { }
...
}

Otherwise people are tempted to scatter generics all over the
place, and it's probably better to encourage them to group similarly
parameterized generics in the same spot for sanity.  It also encourages
people to instantiate their generics in one spot even if they're
calling them from all over.

: The syntax for explicit selection could be foo:(Int)('3','2') which
: prevents the interpretation foo:(Str,Str). OTOH, this might overload
: the :() too much. Could we invent more colon postfix ops?
: Thus the above were foo:[Int]('3','2'). And while we are at it
: since () is more call-like and [] lookup-like we could reserve :()
: for more complicated type literals and use :[] for formal type signatures
: on subs as it is the case for roles.

I think people should say does FooStuff[Int] and automatically alias
all the routines to the Int form so we don't have to scatter :[Int]
all over.  Or if they just say does FooStuff, they get lazily-bound
type parameters.

:  The :: does imply
: indirection of some sort in either case, but it's two very different
: kinds of indirection.  ::($x) can't declare a lexical alias for
: some type, whereas ::T presumably could, though your formulation seems
: more of a unificational approach that would require ::T everywhere.
: 
: In other words, if we do type binding like b, we would probably want to
: generalize it to other binding (and assigning?) contexts to represent
: the type of the bound or assigned object, and at the same time create
: a lexical alias for the bare type.  So we might want to be able to say
: 
: ::T $x := $obj;
: my T $y = $x;
: 
: The prime use of that feature is to ensure type homogenity for
: temporary and loop vars in a certain scope. But the scope in the
: above syntax is not apparent enough---to me at least.

Actually, I was holding those up as bad examples of scope visibility,
so I'm agreeing with you there.  (Which is why I suggested that we
require a my context, even if only implied by the formal paramter list.)

: Thus I opt for an explicit
: 
:subtype T of $obj.type; # or just $obj perhaps?
:T $x := $obj;
:my T $y = $x;

Yuck.  I think that completely obscures the lazy type binding.
Plus you've managed to omit the my, so you've created a global
subtype T.  (Unless, as I'm leaning towards, we make such bare inner
types illegal, and require my, our, or *.)

: With my proposal from above the short form could be
: 
::[T] $x := $obj;
:my T $y = $x;
: 
: or the current form with :()
: 
::(T) $x := $obj;
:my T $y = $x;

I think any lexically scoped declaration should be governed by a my
(either explicitly or implicitly), and that includes type declarations.
A bare :[T] or :(T) outside a declaration is not good enough.
It's okay if there's already a my outside, in which case you're
declaring both the variable and the type, but there also needs to
be a way of scoping my to the type without declaring the variable.
I want to be able to distinguish

my (T) $x := $obj

from

(my T) $x := $obj

And maybe that's just how we should leave it.  I confess that

my [T] $x := $obj
[my T] $x := $obj
method foo ($self: [T] $x) {...}

are prettier, and more reminiscent of generics, but I worry about
confusiion with [$h,[EMAIL PROTECTED] bindings, and with reduction operators.
On the other hand, (T) looks like a cast, and [T] isn't *really*
all that ambiguous.  Given how often these things will occur in
other contexts that use colons for other things, I don't think it's
a very good plan to go with :[T].  These are visually confusing:

my :[T] $x := $obj
method foo ($self: :[T] $x) {...}

Bare [T] would preclude its use in rvalue context, however, as it
might be taken as a reduction operator.  No big loss, in my estimation.
Could maybe allow [my T] there, I suppose.

Larry


Re: Type variables vs type literals

2005-07-01 Thread Larry Wall
On Thu, Jun 30, 2005 at 09:25:10AM +0800, Autrijus Tang wrote:
: Currently, does this:
: 
: sub foo (::T $x, ::T $y) { }
: 
: and this:
: 
: sub foo (T $x, T $y) { }
: 
: Means the same thing, namely
: 
:a) if the package T is defined in scope, use that as the
:   type constraint for $x and $y
: 
:b) otherwise, set ::T to be the most immediate common supertype
:   of $x and $y.
: 
: Is this understanding correct?  I'd like to disambiguate the two cases
: by making ::T in parameter list to always mean type variable (sense b),
: and the bare T always mean type name (sense a)?

I think it would be good to distinguish those, but I've been mulling
over whether ::T should be the syntax for b.  (And also whether b
is the correct way to think about it in Perl 6.)  The problem with
using ::T for autovivify your type from the argument is that ::($x)
doesn't mean that, and it looks like it should.  The :: does imply
indirection of some sort in either case, but it's two very different
kinds of indirection.  ::($x) can't declare a lexical alias for
some type, whereas ::T presumably could, though your formulation seems
more of a unificational approach that would require ::T everywhere.

In other words, if we do type binding like b, we would probably want to
generalize it to other binding (and assigning?) contexts to represent
the type of the bound or assigned object, and at the same time create
a lexical alias for the bare type.  So we might want to be able to say

::T $x := $obj;
my T $y = $x;

and mean something like

(my type T) $x := $obj
my T $y = $x;

In that formulation, the unificational approach looks more asymmetrical:

sub foo (::T $x, T $y) { }

meaning

sub foo ((my type T) $x, T $y) { }

On the other hand, if we continue the trend that multiple my's in the
same scope declare the same variable (possibly with warning), then

sub foo (::T $x, ::T $y) { }

would presumably be okay semantically, even if the second ::T is construed
as warning bait.

But it also goes against the grain to autolexicalize something based on
the sigil, so we probably should consider ::T a variable and require the
sigil everywhere in the absence of a more explicit declaration.  

...Except for the inconvenient fact that it would conflict with the
use of ::T as a literal-but-not-yet-declared type, which is valid
even in signatures, and the b form abrogates that interpretation.

So either we need a different sigil for type variables, or a syntax
for explitly binding and declaring an autovivified type.  (Which,
interestingly, could also be used in rvalue context.)  So maybe we
really want something like

sub foo ((my T) $x, T $y) { }

for the asymmetrical case, and

sub foo ((my T) $x, (my T) $y) { }

for the type unificational case.  Maybe we can shorten that to

sub foo ((T) $x, (T) $y) { }

within an existing my context, such as parameter lists.  And maybe that's
even how we suppress the warning for duplicate my T declaration.  For
bare assignment with run-time type capture, you'd have to say

my $x;
(my T) $x = $obj;

but we also don't have to dup the my when there already is one:

my (T) $x = $obj;
my (T) $x := $obj;

In either case, the actual type is bound rather than assigned, but I
don't think that makes any effective difference since types are always
represented by object refs...

=begin hole-poking mode

Larry


Re: Type variables vs type literals

2005-07-01 Thread Larry Wall
On Fri, Jul 01, 2005 at 11:51:55AM -0700, Larry Wall wrote:
: So either we need a different sigil for type variables, or a syntax
: for explitly binding and declaring an autovivified type.  (Which,
: interestingly, could also be used in rvalue context.)

I neglected to provide an example of this, but it'd be something like

$x = (my T) $y;

to declare that T is whatever type $y happens to be when evaluated.

It would have to be a special form, though, since it needs to expect
a term after it rather than an operator.  And it would require the
absence of anything following T, since (my T $x) means something
entirely different, and in fact requires an operator to follow.
I don't see a better approach offhand, unless it's [my T], which
would have to be just a special, and risks visual confusion with
lists and reduction operators.  So I'm still thinking (T)/(my T)
is the better approach.  But it could use more collective mulling.

Larry


Re: Type variables vs type literals

2005-07-01 Thread Larry Wall
Perhaps type parameters to roles could also be written in (T) notation:

role Tree[(Returns)] {...}

but that would imply the parameter name is Returns rather than
returns.  Maybe that's okay, since it's usually a positional
parameter or a special of form anyway.

Larry