Type Fixing

That kinda breaks the whole thing apart. Now myShape looks like a Shape, but doesn't quack like a Shape. And you'll have a hard time figuring out whether it's actually a valid Shape further down in the code.

1 Like

Which is precisely why you'd need to set it before using it. This is the real limitation of this approach. Since fixed requires an initializer, and the initializer is assigned to the variable, it would be preferable that the initializer always be a proper object. When I try to reduce this away, I end up back at explicit type declaration, and all of it's implementation issues. Unfortunate.

That being said, there are still potential ways around this, but they require null to be handled differently, which also requires that I keep the limitation of not allowing the "type" to be null. What if we don't bind the initializer to the variable, assign null instead, but use the type of the initializer to fix the type? There's 2 different possibilities here.
a. Allow primitive initializers to be assigned, but use null for objects. This is consistent with the use of null, but inconsistent behavior.
b. Initialize undefined to primitive types and null to object types. This has the annoyance of requiring that the initial useful assignment be a second step.
c. Make use of the let x : type notation only for object types such that this is valid

let fixed x: Shape = new Square;

I prefer option c. However, there are some caveats....

  • The fixed keyword might be considered optional if : type is used, though I wouldn't recommend it. Personal opinion on that.
  • The : type notation couldn't be used for primitives or when the constructor is either not available, not a function, or has no object prototype member.

The reason for the second caveat is that one of the clear goals is to implement typing in a way that does as close to nothing as possible to force types on the engine in any way that it is not already somewhat doing. So this means we cannot use keywords for primitive types. Likewise, using the boxed primitive object built-ins would require that any assigned primitive also be pre-boxed. Remember that assignment to a fixed variable won't do any type casting, so assignments would require explicit casting.

So far, it looks like the valid syntax should be:

//for variables typed from constructor functions
//The initializer is optional since the type is provided.
//Can be initialized with null or undefined
var fixed token: Constructor = initializer;
let fixed token: Constructor = initializer;
const fixed token: Constructor = initializer;

//for variables implicitly assigned a type.
//Initializer is required. Cannot initialize with null or undefined
var fixed token = initializer;
let fixed token = initializer;
const fixed token = initializer;

//first fixed means "fnToken" can only be reassigned to a function
fixed function fnToken(fixed token1, fixed token2) {}

//Is a constructor-typed form possible here?
let a = {
   //Only an implicit form available right now
   fixed token: initializer,
   fixed fnToken(fixed token1, fixed token2) {}
}

//At odds over allowing fixed on a class declaration...
class Ex {
   fixed #pvtVar1: Constructor = initializer;
   fixed #pvtVar2 = initializer;
   fixed #pvtFn(fixed token1, fixed token2);
   fixed pubVar1: Constructor = initializer;
   fixed pubVar2 = initializer;
   fixed pubFn(fixed token1, fixed token2);
}

Given the fact that : type has already been allocated for type declarations, but objects use : to delineate the initializer, how can an explicit type declaration work there?

Peanut gallery observation: "fixed" is not a reserved word. That's probably a fatal flaw right there.

Lexical grammar - JavaScript | MDN is an unofficial list of reserved keywords (though MDN is a pretty good reference). Good luck getting TC39 to reserve another word for this, or to specify grammar symbols to provide that capability. You need some way in that will not break the Internet - and that's hard.

It's not a reserved word, but the proposed syntax is also a syntax error, so nothing would be breaking.

> const fixed token = 2;

const fixed token = 2;
      ^^^^^

Uncaught SyntaxError: Missing initializer in const declaration

A lot of new proposals plan on utalizing words that aren't currently reserved - it can be done as long as you are careful.

1 Like

Could explicit types be attached to the fixed modifier? Something along the lines of...

fixed<Constructor> token: initializer

The reason I didn't go that route is that:

  • In prior discussions on different topics, I learned from TC39 members that the : type syntax was reserved specifically for type specifications. It's best to make use of what's already there.
  • Because of the above point, it's a consistentcy issue to have the type specified in a prefixed mannor just for this one-off case.

I've been considering something like this:

let a = {
   // Either
   fixed token::Constructor: initializer
   // or 
   fixed token : initializer::Constructor
}

I like the former better because the latter looks like it opens the possibility for something like:

let fixed token = new Square::Constructor;

It needs to remain obvious that the type is part of the declaration.

It can be a soft keyword; because the use case is restricted to only a specific context.

why not add type hints just like python ,IDE can use this @theScottyJam @rdking

At least in my opinion, a type hint is no better than a comment. It does little to actually perform the intention of having types (strictly controlling the expected shape of a variable). ES is a dynamically typed language. The idea I'm presenting can push ES into being a dynamically typed language with optional explicit types. Doing so would give people the type control they're looking for without requiring a complete overhaul of how ES engines handle types.