On Wed, Jul 06, 2005 at 03:29:36PM +0200, "TSa (Thomas Sandlaß)" wrote: : 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?
It achieves guaranteed *late* binding of types, whereas generics/roles are biased towards early binding (class composition time, usually at "compile time"). : >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? Would be a late type binding in that case. : Something like unary operator does? Don't follow that. : Into which scope do these role instanciations go? Unary role instantiations always go into the "currently composing class" (and maybe module, if we admit "sub" roles). : Does "does *FooStuff[Int]" mean global? It means to look for FooStuff in the global namespace and nowhere else. : >: > ::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. 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. : 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 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 *. 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? : 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. Yes, it's currently just a promise that T will be declared by the time we need it. Otherwise T would be taken as an illegal bareword. : 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? 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 idea breaks down. : 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 ;) Okay, you've used ::Type as a type variable--now how do you declare that you simply want Type treated as a forward declaration of "Type". I'm not quibbling with the desire to bind types to type variables. It's just we've got a conflict in the definition of what :: means that we'll have to resolve one way or another. =begin WAFFLE I suppose we could reserve ::Type as the variable form, and then require an actual forward declaration for the other form: my class T {...} my T $x; ... my class T { has $.x; } Note that in this case, the second "class T" probably should default to "my" instead of "our", or otherwise produce some kind of warning if there's a "my" vs "our" conflict. Similarly class T {...} my T $x; ... class T { has $.x; } requires both references to be to "our" T. That seems okay, and maybe even consistent, but we'll have to think about the relationship of ::T and ::($x) a bit more, and how it differs from ::{$x} (or ::$x for that matter). And if we're changing the meaning of :: from "this is a known name" to "this is an unknown type", whether consistency requires that $($x) be the explicit symbolic deref form. I think I'd prefer that symbolic refs were huffmanly longer than that. Even if we settle on ::T for type variables, I still think we have to say that they are legal only in a declarative context. These would be fine my ::T; # unbound type variable my ::T $x; # type variable bound when $x is bound but in rvalue context I don't think ::T should imply declaration, but rather refer to an earlier declared ::T, or fail. An explicit declaration can still be done $x = (my ::T) $y to get ::T bound to the type of $y "en passant". Probably. =end WAFFLE Larry