Ticket #247 (new defect)

Opened 3 years ago

Last modified 2 years ago

Scoping for "type" directive

Reported by: lth Assigned to: anonymous
Type: defect Priority: trivial
Component: Spec Version: 4
Keywords: Cc: brendan, jeffdyer, graydon, cormac, dherman, pascallouis

Description

(Summary of email conversation; pls discuss)

PACKAGE:

type must surely create bindings in the variable object, or type definitions can't be exported, and that would be a misfeature.

CLASS:

type should be implicitly static and should bind in the variable object of the metaclass (ie it's an instance property of the metaclass), so that type T in class C is available at compile time as C.T.

FUNCTION/BLOCK:

type should probably be bound in the block object (like let), but this is really not a major use case and for consistency's sake it would probably be just as well if it were bound in the variable object (ie, if it were hoisted like var).

Alternatively, we could restrict type to being defined at top level in a function, like we do for nested functions. (Personally a favor this, because hoisting is a little evil and we don't want to propagate evil.) On the other hand, type has fewer problems than const since type definitions always have a right-hand-side and it only references other type stuff that has already been defined.

Attachments

Change History

  Changed 3 years ago by cormac

If types in classes are static, then we forbid useful examples like the following:

class C.<X> {
    type pair = [X,X];
    ...
}

This suggests that we should have both static and non-static types in classes, although that does introduce additional complexity.

We could future-proof by requiring that types in classes be explicitly marked "static".

  Changed 3 years ago by lth

Proposal:

  • "type" is like "var" --- it hoists, creates fixtures in a class context, etc
  • "type" can be qualified with "let" and "static" with obvious meaning

  Changed 3 years ago by lth

Although I'm not sure how good Cormac's example is. His example is not forbidden because the reference isn't C.pair (which is illegal), but rather C.<int>.pair, which works even if pair is static.

  Changed 3 years ago by cormac

If the type variable X is in scope in static contexts, then we can have things like:

class C.<X> {
     static X x;
}

which leads to multiple variable C.<int>.x and C.<bool>.x, and seems clearly wrong.

Hence, X should not be in scope in static contexts, forbidding its use in static bindings,like above, in which case the .<int> when referring to static variables is unnecessary, and so if pair is static, then C.pair should be ok. That is:

class C.<X> {
   static type pair1 = [X,X]; // forbidden
   static type pair2 = [int,int]; // ok
   type pair3 = [X,X]; // ok
}
C.pair2   // ok
C.pair3   // static access to instance member
(new C.<int>()).pair3    // ok

  Changed 3 years ago by cormac

Let me retract my last comment. I was working off a different model for generic classes.

  Changed 3 years ago by pascallouis

  • cc changed from brendan,jeffdyer,graydon,cormac,dherman to brendan, jeffdyer, graydon, cormac, dherman, pascallouis

follow-up: ↓ 8   Changed 3 years ago by pascallouis

Are recursive types like

type IntList = (undefined, {head:int, next:IntList});

allowed?

in reply to: ↑ 7   Changed 3 years ago by brendan

Replying to pascallouis:

Are recursive types like {{{ type IntList? = (undefined, {head:int, next:IntList}); }}} allowed?

No, see the minutes near the end of the section starting here:

http://wiki.ecmascript.org/doku.php?id=meetings:minutes_may_25_2006&s=recursive#multiple_compilation_units

We decided not to impose a simple but exponential (Amadio/Cardelli) or complicated and still quadratic (Palsberg/Schwartzbach) algorithm on all implementations, tell users who fall off this cliff to use nominal types or factor structural types to avoid recursion (this was done for iterators and generators, to good effect, I think), and re-consider recursive structural types in the future.

/be

  Changed 3 years ago by lth

The Nov 13 2007 phone meeting revealed a split in the committee about the nature of parameterized classes.

Some (Lars, Brendan) thought parameterized classes were like C++ templates in the sense that you get new static members per instantiation (so C.<int>.x is not the same as C.<bool>.x, if x is defined as static in C); in this view, C by itself has no x (it is indeed somewhat unclear exactly what C by itself means), but the type parameter to C is available to static and instance properties alike. In other words, this is possible:

   class C.<T> {
      var x : T
   }

Others (Graydon, Cormac) thought parameterized classes were like Java generics, where if there is a static x it appears as C.x (no instantiation is required), and the type parameter to C is not available to static definitions. The above definition of C would be illegal.

The issue is discussed near the bottom of the Feb 21 2007 minutes: http://wiki.ecmascript.org/doku.php?id=meetings:minutes_feb_21_2007 where the conclusion indeed supports the "single static" view from what I can tell. (These meeting notes also make it clear that type definitions in the class do not hoist to the class's variable object and are not available to static code inside the class. So C.T is not legal.)

The current draft language is known to make use of static methods that reference the type parameters of the surrounding class in two instances: in the meta::invoke method on Enumerator, and in a utility method inside the Map class. The latter could go away; the former feels more integral to the design, but could be replaced by a * in the worst case.

  Changed 3 years ago by lth

BTW, C# follows C++ on this.

  Changed 3 years ago by lth

See also #289, which talks about the same problem from the POV of namespace.

  Changed 2 years ago by lth

  • priority changed from major to trivial

Resolution for namespace and type both:

They are allowed in classes. They must have the 'static' keyword. They can be used in the definitions of other static entities in the class body. Because they are static, Cls.T and Cls.ns can be used as annotations elsewhere. If Cls is parameterized then by resolutions in #247 and elsewhere it is Cls.<U>.T etc.

Note: See TracTickets for help on using tickets.