Optional argument types

# Dmitry Soshnikov (7 years ago)

Just a curiosity -- what is the current state of the optional argument types proposal (if there is one)? Isn't it too late to propose?

Just recently participated in a discussion when these optional types are wanted to be used. Having a build-tool with pre-processing it's not that hard to add them manually to our sources, of course e.g.

function foo(/string/ bar, /number/ baz) { ... }

We could even add a small language extension having such preprocessors -- instead of comments use real keywords/constructor names:

function foo(String bar, Number baz) { ... }

If these are constructor names, then even new keywords are not needed, and the code just translates into:

function foo(bar, baz) { if (typeof bar != 'string') throw TypeError(...); if (typeof baz != 'number') throw TypeError(...);
}

That's it, literally it does only this and nothing else.

(Instead of typeof can be used [[NativeBrand]] check of course)

The same can go to the return values.

This is only for arguments, not simple variables may "carry type" (since these are the values carry types, not the vars), just simple runtime type checking in the prologue of a function.

(I had have proposed similar before using JavaDocs instead gist.github.com/1186853, however, simple optional types could be better).

Does JS need this much?

Dmitry

# Rick Waldron (7 years ago)

On Mon, Sep 24, 2012 at 1:40 PM, Dmitry Soshnikov < dmitry.soshnikov at gmail.com> wrote:

Hi,

Just a curiosity -- what is the current state of the optional argument types proposal (if there is one)? Isn't it too late to propose?

Just recently participated in a discussion when these optional types are wanted to be used. Having a build-tool with pre-processing it's not that hard to add them manually to our sources, of course e.g.

function foo(/string/ bar, /number/ baz) { ... }

We could even add a small language extension having such preprocessors -- instead of comments use real keywords/constructor names:

function foo(String bar, Number baz) { ... }

If these are constructor names, then even new keywords are not needed, and the code just translates into:

function foo(bar, baz) { if (typeof bar != 'string') throw TypeError(...); if (typeof baz != 'number') throw TypeError(...); }

That's it, literally it does only this and nothing else.

(Instead of typeof can be used [[NativeBrand]] check of course)

The same can go to the return values.

This is only for arguments, not simple variables may "carry type" (since these are the values carry types, not the vars), just simple runtime type checking in the prologue of a function.

(I had have proposed similar before using JavaDocs instead gist.github.com/1186853, however, simple optional types could be better).

Does JS need this much?

Check these out:

strawman:guards, strawman:trademarks

# Allen Wirfs-Brock (7 years ago)

On Sep 24, 2012, at 11:13 AM, Rick Waldron wrote:

... Check these out:

strawman:guards, strawman:trademarks

Rick

But, getting back to Dmitry's original question. These haven't been accepted as proposal for ES6 and it it is also certainly "too late" for that to happen. Future editions, beyond ES6 is very much open for discussion.

# Dmitry Soshnikov (7 years ago)

On Mon, Sep 24, 2012 at 11:26 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

But, getting back to Dmitry's original question. These haven't been accepted as proposal for ES6 and it it is also certainly "too late" for that to happen. Future editions, beyond ES6 is very much open for discussion.

I think it's just the matter of the need. If these optional argument types are very needed by devs, then it's probably not a big deal to add them to the standard -- after all it's still in the draft, not published (it's just a small section on generating the prologue, isn't it?).

If they are not much needed, then even future editions won't be so essential in this respect.

Dmitry

# Aron Homberg (7 years ago)

Just to know the process better: For such ideas, who is allowed to write a strawman-page in the wiki?

<noise>

Personally, I would like guards without that magic '::' syntax. Why reinventing the wheel? Just allowing/checking optional type's would be great:

var Number|Boolean|Null abc = null; var String foo = 'bar'; var withoutType = 'yes';

function optType(HTMLElement|String domEl, withoutType='again') { // Nice lang :) }

But this is only noise... :)

</noise>

2012/9/24 Dmitry Soshnikov <dmitry.soshnikov at gmail.com>

# Allen Wirfs-Brock (7 years ago)

On Sep 24, 2012, at 12:16 PM, Aron Homberg wrote:

Just to know the process better: For such ideas, who is allowed to write a strawman-page in the wiki?

Only Ecma members can directly post to the wiki. If you aren't an official representative of an Ecma member you can host your proposal on your own site and/or post it in a message to es-discuss. If you want it to appear on the TC39 wiki you have to convince a member to take responsibility for submitting it.

The restrictions on posting to the wiki basically derive from the Ecma Intellectual Property policies.

# Andreas Rossberg (7 years ago)

On 24 September 2012 20:53, Dmitry Soshnikov <dmitry.soshnikov at gmail.com> wrote:

I think it's just the matter of the need. If these optional argument types are very needed by devs, then it's probably not a big deal to add them to the standard -- after all it's still in the draft, not published (it's just a small section on generating the prologue, isn't it?).

It actually is a very big deal. Getting such a feature right is highly non-trivial, with lots of ugly JS corner cases to worry about. Let alone a good runtime cost model.

# Andrea Giammarchi (7 years ago)

... or the ability to boost up a lot JIT and performances ... but I agree on the non trivial, rich in ugly JS corner cases too, e.g. string as primitive VS String as instanceof

# Alex Russell (7 years ago)

Perhaps, but it's easy to be too naive about what VMs do (and don't do). Best to design for semantics with performance in mind, not the other way around.

In any case, would you be looking for nominal or structural type tests here?

On Sep 25, 2012, at 11:44 AM, Andrea Giammarchi <andrea.giammarchi at gmail.com>

wrote:

... or the ability to boost up a lot JIT and performances ... but I agree on the non trivial, rich in ugly JS corner cases too, e.g. string as primitive VS String as instanceof

# Andrea Giammarchi (7 years ago)

That's a hell of a question ... shapes speaking I'd say structural, since AFAIK shapes are those boosted up more, isn't it?

That would solve String VS string and Array VS Arguments which is, I believe, kinda desired.

Which one would you chose ?

# Andreas Rossberg (7 years ago)

On 25 September 2012 15:31, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

That's a hell of a question ... shapes speaking I'd say structural, since AFAIK shapes are those boosted up more, isn't it?

That would solve String VS string and Array VS Arguments which is, I believe, kinda desired.

Which one would you chose ?

I assume that most people would probably prefer structural types in principle, but the problem is that they induce far, far more expensive runtime checking (easily an order of magnitude). Which is why guards and trademarks were proposed as a more conservative, nominal mechanism.

Generally speaking, retrofitting something type-like on an untyped language is a very hard problem. It has been tried with many languages and has succeeded for very, very few. You can read lots and lots of research papers on the subject.

Fortunately, though, we have top-notch expertise on that topic on TC39, e.g. Sam TH. ;)

# Andrea Giammarchi (7 years ago)

then nominal will be? :)

# Alex Russell (7 years ago)

It's far too early to tell. I strongly prefer structural, but again, backing a type system into ES isn't something to do lightly. It has huge consequences that extend well beyond the grammar changes.

# Andrea Giammarchi (7 years ago)

I wonder if nothing came out at ES4 time about this topic ... AS2 ES4 like approach wasn't that bad, imho

function doStuff(key:String, value:Object):Boolean {}

this was permissive without types ...

function setIntoMap(map:Map, key, value:Object):Map {}

this was good help before execution ... this wasn't big deal with overloads ( not supported as it is already in JS )

At that time, I really liked this approach but I am sure you know it pretty well too :)

# John Lenz (7 years ago)

As a point of reference the Closure Compiler doesn't choose but supports both record types (structural) and "instanceof" (nominal) types in the type system. The big down side of nominal types in JS is there is no way to express interfaces (the Closure Compiler type system supports them with annotations), so unless a means is added for expressing interfaces in some form (mixins, traits, or what have you) that can respond to an "instanceof", nominal types are simply not expressive enough.

The problem with structural types in a dynamic language is that the checks are potentially costly. I'm not sure this is true for today's VMs or not (are the hidden classes they use sufficient to make these checks efficient?) but if nothing else runtime support for them will require additional bits. Structural types are also intentional sloppy, related types can look the same. For example, the structural question of "do you have an 'id' field" doesn't answer for the intended use of that field. Of course, being able to ask the question in an efficient manner for complex structures would be a huge win over what needs to happen now if you want to check for structural compatibility.

For writing tests, I've always been in favor of object that override type checks regardless of whether they are structural or nominal. I'm not sure what this means for structural checks.

# John Lenz (7 years ago)

that should have been "unrelated structures can look the same". I should also note that the Closure Compiler types system was based off the ES4 proposal, if you want to see how things played out.

One thing that I have seen specifically, is that supporting "non nullable" types, and distinguishing between "undefined" and "null" in the type signature creates a fair amount of busy work ("type casts" to remove nullability) for larger projects. Although, the provide some level of comfort for small projects (where everything is in your control).

# Andreas Rossberg (7 years ago)

On 25 September 2012 17:50, John Lenz <concavelenz at gmail.com> wrote:

The problem with structural types in a dynamic language is that the checks are potentially costly. I'm not sure this is true for today's VMs or not (are the hidden classes they use sufficient to make these checks efficient?) but if nothing else runtime support for them will require additional bits.

Hidden classes are effectively nominal types, so they don't provide much insight into implementing structural checks.

The problem with (dynamic) structural checks is that they have to go deep. In the higher-order case (i.e. anything involving function values or mutable state -- that is, any object) a lot of checking has to be deferred to later uses of the value. Consequently, these cases generally require dynamically wrapping checked values with respective type information.

Structural types are also intentional sloppy, related types can look the same. For example, the structural question of "do you have an 'id' field" doesn't answer for the intended use of that field.

This is a frequent argument against structural typing, but IME, it is pretty much irrelevant in practice (and certainly no more sloppy than no typing).

Also note that private names would probably give you a way to enforce nominal behaviour.

# Brendan Eich (7 years ago)

John Lenz wrote:

that should have been "unrelated structures can look the same".

Right. Robert O'Callahan mocks this as "structural types are about field names, nominal types are about class names".

Clearly, "duck typing" structural protocols (iteration in ES6) have advantages as well as costs. Array-like is the first of this kind. We aren't against such things, the issue Andreas raises is the researchy nature of doing anything you could call a type system for a language such as JS -- whether structural or nominal types -- or both -- are included.

I should also note that the Closure Compiler types system was based off the ES4 proposal, if you want to see how things played out.

Did you include all the "like" non-type crazy?

One thing that I have seen specifically, is that supporting "non nullable" types, and distinguishing between "undefined" and "null" in the type signature creates a fair amount of busy work ("type casts" to remove nullability) for larger projects.

Yes, it's like const. You have to rule out null at an API boundary or other chokepoint, and then go non-null in the "kernel". C and C++ programmers do this by hand (references in C++ only help so much -- and they give no runtime safety).

# Andreas Rossberg (7 years ago)

On 25 September 2012 17:57, John Lenz <concavelenz at gmail.com> wrote:

One thing that I have seen specifically, is that supporting "non nullable" types, and distinguishing between "undefined" and "null" in the type signature creates a fair amount of busy work ("type casts" to remove nullability) for larger projects. Although, the provide some level of comfort for small projects (where everything is in your control).

Indeed, that is one of the things that is trivial to deal with when designing a language with types from the very start (where making types null-free by default is easy and damn useful), and very difficult when retrofitting types later (where all kinds of weird patterns might already have evolved).

Regarding null vs undefined in JavaScript, the right thing to do would probably be making as few distinctions on the type level as possible.

# Andrea Giammarchi (7 years ago)

then how about forgetting ducks and classes, going typeof without implicit cast?

function doStuff(i:number, key:string, u:undefined, b:boolean, fn:function):object {}

where null will still be under the object type.

Would this be a decent compromise or a pointless effort for no benefits?

# Dmitry Soshnikov (7 years ago)

On Tue, Sep 25, 2012 at 7:37 AM, Andreas Rossberg <rossberg at google.com>wrote:

On 25 September 2012 15:31, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

That's a hell of a question ... shapes speaking I'd say structural, since AFAIK shapes are those boosted up more, isn't it?

That would solve String VS string and Array VS Arguments which is, I believe, kinda desired.

Which one would you chose ?

I assume that most people would probably prefer structural types in principle, but the problem is that they induce far, far more expensive runtime checking (easily an order of magnitude). Which is why guards and trademarks were proposed as a more conservative, nominal mechanism.

Generally speaking, retrofitting something type-like on an untyped language is a very hard problem. It has been tried with many languages and has succeeded for very, very few. You can read lots and lots of research papers on the subject.

Fortunately, though, we have top-notch expertise on that topic on TC39, e.g. Sam TH. ;)

I believe all this is true, and this is why I underlined in the first letter that it's kind of not a "type system" by itself, but only the runtime (yes, runtime) check of the "type-tags" of the argument values. And only the argument values.

That's said, introducing the types for casual vars, like:

let x :: Number = 10;

pushes the responsibility of type carrying to the variable. Thus changing the semantics of the environments model, where the vars don't carry the type, but just reference to the values which carry the type. The line above, if to accept such a "type system" would look like x = "foo" is the error then.

Having this "type hints" only for arguments, reduces the problem only for checking the "type-tags" of the arguments, in the function's prologue. And it can be done only in runtime (a function can be applied in different ways, and it's not possible to determined lexically with what "types" of arguments, so only the runtime).

By "type-tags" I mean a generic way of testing. Not the typeof result, not the instanceof. But e.g. the [[NativeBrand]] (for natives) + instanceof for custom constructors (the later is just an extension).

This gives the ability not to think about it as a "type system", but just as "type hints for arguments". Because again, after the arguments have been checked for the "type-tag" at activation, the argument vars themselves can be rebound to the values of different types, underlining that the variable are not related with the types, and the type annotations for function arguments are just type annotations for checking the types of passed values at only activation.

This is kind of scheme I have in mind. I understand all the consequences of (not)optimizations and runtime coasts, but if devs are need these type checks, then they do this anyway manually (and usually in the prologue of the functions) at runtime today. So providing this would make it just implicit. Still with understanding that this is a runtime check, which may decrease the speed of function execution -- but it's already decreased once they do this manually anyway.

This model btw is used in PHP as well (type hints only for function arguments, but any var can be reassigned to the value of different type, underlining that this not a "type system").

Today's check to which we can compile our sources with a build-tool is:

function foo(String bar, Widget baz) { ... }

is:

if (bar.[[NativeBrand]] != "String") throw TypeError(...); if (!(baz instanceof Widget)) throw TypeError(...);

(it's easy to distinguish which type-tag, either [[NativeBrand]] or the instanceof, to use in order to check which value, natives are known, and all others may be checked with the instanceof). Thus, the later is just an extension, we can check only for natives, not bothering with constructors/classes.

Anyways, since it's hard to implement it now and since it may coast too much in respect of VMs optimizations, I think any big project may solve this problem with own implementations with pre-processors/compilers. Thus, some exact syntactic form (if it will be widely adopted by some big community) can be then reused for standardization.

P.S.: and to think about type-system in JS is hard, since it doesn't have it. It has just a mess with typeof vs. instanceof vs. [[NativeBrand]] vs. "ducks" (aka "[[NativeBrand]]-like objects"). And therefore, again, those "type-hints" for args are not about a "type-system".

Dmitry

# Oliver Hunt (7 years ago)

I'm very concerned about the interaction of boxed primitives and these type guards, especially in the context of multiple global objects (i.e. the standard browser environment).

I'm not sure what the best solution to this is -- the [[NativeBrand]] concept worries me as it hides the potential for different types being passed into an ostensibly singly typed variable. Likewise I'd be worried about instanceof causing problems for the exact opposite reason (eg. instanceof Array not working across globals).

I'm not sure what the spec currently says w.r.t implicit boxing off the top of my head, but I would be prefer that implicit boxing would not be allowed.

Then we could have at least a few primitive types: number, bool[ean], string, function, say. The primitive names would take precedence over the result of any lookup, and if someone wanted to force a lookup then they could use ""'s. This also would mean that Number and number as types would be (correctly) distinguished.

I'm unsure what the default values for a primitive typed variable should be, but I'm generally opposed to TDZs.

# Dmitry Soshnikov (7 years ago)

On Tue, Sep 25, 2012 at 11:18 AM, Oliver Hunt <oliver at apple.com> wrote:

I'm very concerned about the interaction of boxed primitives and these type guards, especially in the context of multiple global objects (i.e. the standard browser environment).

I'm not sure what the best solution to this is -- the [[NativeBrand]] concept worries me as it hides the potential for different types being passed into an ostensibly singly typed variable. Likewise I'd be worried about instanceof causing problems for the exact opposite reason (eg. instanceof Array not working across globals).

I'm not sure what the spec currently says w.r.t implicit boxing off the top of my head, but I would be prefer that implicit boxing would not be allowed.

Then we could have at least a few primitive types: number, bool[ean], string, function, say. The primitive names would take precedence over the result of any lookup, and if someone wanted to force a lookup then they could use ""'s. This also would mean that Number and number as types would be (correctly) distinguished.

I'm unsure what the default values for a primitive typed variable should be, but I'm generally opposed to TDZs.

In real practice though, I don't think there can be the cases when "strings" or new Strings are worth to distinguish and to work separately in the code (I mean exactly to route the code differently based on it). That's literally -- I cannot imagine any practical example of it (OK, I cannot imaging even a theoretical example of routing the code based on primitive vs. box-values).

The only thing when "string" vs new String arrives is exactly the errors of trying to test the type of passed arguments as:

if (typeof foo == "string") { ... }

and then their new String doesn't work for them. Then they switch to [[NativeBrand]] checks instead.

So for foo(String bar) { ... } in real practice both, "string" and new String should pass I think.

P.S.: actually, the one theoretical/practical distinguishing example is when a programmer say want to save some state on the passed value, e.g.:

foo(String bar) { bar.count = 10; }

It won't work for primitives (since an intermediate wrapper is destroyed after property resolution). But this is kind of the hint for the programmer himself that he should pass then new String always there, but not just "strings".

And foo(String bar) for new Strings, and foo(string bar) for "strings" interesting by itself, but introduces new keywords, and also keeps logical separation b/w primitives vs. boxes. In real practice again, programmers don't even think about it in application tasks and if so, try to avoid.

Dmitry

# Oliver Hunt (7 years ago)

function f(Boolean b) { if (b) ... }

f(false)

has very different semantics from

function f(b) { if (b) ... }

f(false)

Likewise eliding boxing is very very hard if anything happens to mutate any portion of the proto chain for String, etc.

You also run into semantic issue if you do:

Foo = String

function f(Foo h) { .... }

Should this box? If it should box then what we're saying is that the semantic behaviour of

function f(Foo h)

is

function f(h) { if (!Object.isObject(h)) h = new Foo(h) if (!(h instanceof Foo)) throw ...; ... }

Which is the horror of C++ implicit constructor conversions

If we say that

Foo = String; function f(Foo h) ..

is semantically different from

function f(String h)

then we're implying that String has become a context dependent keyword (which is what i meant to imply for my prior primitive type names)

# Dmitry Soshnikov (7 years ago)

On Tue, Sep 25, 2012 at 12:01 PM, Oliver Hunt <oliver at apple.com> wrote:

function f(Boolean b) { if (b) ... }

f(false)

has very different semantics from

function f(b) { if (b) ... }

f(false)

Yeah, this seems the best example, forgot about it; thanks.

Likewise eliding boxing is very very hard if anything happens to mutate any portion of the proto chain for String, etc.

You also run into semantic issue if you do:

Foo = String

function f(Foo h) { .... }

Should this box? If it should box then what we're saying is that the semantic behaviour of

function f(Foo h)

is

function f(h) { if (!Object.isObject(h)) h = new Foo(h) if (!(h instanceof Foo)) throw ...; ... }

Which is the horror of C++ implicit constructor conversions

If we say that

Foo = String; function f(Foo h) ..

is semantically different from

function f(String h)

then we're implying that String has become a context dependent keyword (which is what i meant to imply for my prior primitive type names)

Yeah, this one is too; thanks.

Yes, it's actually harder to do (though unfortunately based on the existing language issues, not the application issues. But we cannot ignore them of course).

In this view, yes, JS is not ready to go with this in production and at standard level. And as for custom projects -- then, that's said, can solve this issue in own manner with pre-processors.

Thanks again,

Dmitry

# Andrea Giammarchi (7 years ago)

Dmitry I think in this view the proposal having "primitives" rather than instanceof makes more sense and is probably what you need, right?

string s won't accept instanceof String, that's what you want ... 'cause you don't want pointless objects wrappers around neither, isn't it?

You want function, string, boolean, undefined, number, and object ... which are all universally valid, included the null as object when nullable is desirable, isn't it? This should cover 80% of use cases already without much effort.

Anyway, the good part of JavaScript is that you can wrap everything runtime and debug it without problems during assignment so that you can create a function wrapper able to define a behavior and disable this behavior in production, as suggested in my 2007 post about strict type JavaScript .. is a wrapper for function, gonna work for these cases too and the way you expect/want.

I still would like to know why the typeof, as hint, is a bad idea thought :-)

br

# Brendan Eich (7 years ago)

Andrea Giammarchi wrote:

then how about forgetting ducks and classes, going typeof without implicit cast?

No.

Why the desperation to get something -- anything -- even a half-baked idea based on broken old typeof? Where's the fire?

Sorry, at this point in the thread I have to start pushing back!

function doStuff(i:number, key:string, u:undefined, b:boolean, fn:function):object {}

where null will still be under the object type.

Would this be a decent compromise or a pointless effort for no benefits?

The latter -- sorry, have to call it as I see it. You've heard from Andreas, Alex, and Allen too.

Types are hard. This doesn't mean "no, never". But big brains are still researching the general topic, and btw what Dart has can't be called types according to the researchers and literature I trust.

be

# Andrea Giammarchi (7 years ago)

well ... I was asking indeed why that was not even an option ... is not half backed being typeof the most used check ever for arguments and variables but I got your point :-)

br

# John Lenz (7 years ago)

On Tue, Sep 25, 2012 at 9:12 AM, Brendan Eich <brendan at mozilla.org> wrote:

John Lenz wrote:

that should have been "unrelated structures can look the same".

Right. Robert O'Callahan mocks this as "structural types are about field names, nominal types are about class names".

Clearly, "duck typing" structural protocols (iteration in ES6) have advantages as well as costs. Array-like is the first of this kind. We aren't against such things, the issue Andreas raises is the researchy nature of doing anything you could call a type system for a language such as JS -- whether structural or nominal types -- or both -- are included.

I should also note that the Closure Compiler types system was based off

the ES4 proposal, if you want to see how things played out.

Did you include all the "like" non-type crazy?

It isn't a complete implementation and completely static (runtime type check injection is optional and rarely used).

# Alex Russell (7 years ago)

On Tue, Sep 25, 2012 at 8:54 PM, Brendan Eich <brendan at mozilla.org> wrote:

Andrea Giammarchi wrote:

then how about forgetting ducks and classes, going typeof without implicit cast?

No.

Why the desperation to get something -- anything -- even a half-baked idea based on broken old typeof? Where's the fire?

Sorry, at this point in the thread I have to start pushing back!

I'm at the same point here.

I want both functions to be able to guard their arguments and declare their returns. Hell, in early Traceur we event designed the Traits system so that Traits can act like interfaces for this purpose.

But I'm not willing to rush this, nor give up on structural typing for no good reason, nor endlessly revisit this. We can perhaps make progress on this in ES7...but this thread probably isn't going to be the basis for that.

# Andrea Giammarchi (7 years ago)

surely there's nothing to rush about, we survived already until now, no reason to go for a quick solution and mine was just a proposal based on the fact that most of the time contracts are based on primitives.

However, If the problem is typeof null then ES should fix that first but AFAIK it came back to "object" at some point even under "use strict" directive and I never understood why ...

primitives also means no wrappers allowed, which is a good practice, generally speaking.

However, primitives does not mean "no Classes allowed" 'cause s:string and s:String could be both valid, and different, one typeof, one instanceof, as well as a:Array rather than just a:object where latter one would be permissive while first one will look for instanceof Array.

The cross frame is nowadays a non-realworld-problem, I don't know any application that uses direct frames access rather than postMessage or JSONP ... in both cases instanceof Array should simply work ... but of course as long as it's possible to access other frames there could be a problem ... in that case, the function that would like to accept Array from any other window can specify a:object and do the [[Class]] check or use Array.isArray to ensure the type after ... create cross frames problems for a type-hint specification when the cross frame is disappeared from basically every library is a non-sense, imho ... who wants to allow such security problematic contract can use his own check, am I wrong?

As summary, string, number, boolean, undefined, function, null, object, as allowed types would cover already many needed cases, adding Array, Object, GenericScopedConstructor, global.name.spaced.Class on top of types can cover 100% of cases I know.

Last but not least, if all this won't speed up a thing but actually will decrease JS performances, as Alex pointed out at some point, I would vote for then don't no matter what.

br

# Alex Russell (7 years ago)

On Wed, Sep 26, 2012 at 1:06 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

surely there's nothing to rush about, we survived already until now, no reason to go for a quick solution and mine was just a proposal based on the fact that most of the time contracts are based on primitives.

However, If the problem is typeof null then ES should fix that first but AFAIK it came back to "object" at some point even under "use strict" directive and I never understood why ...

because it was a breaking change, a refactoring hazard, and having different behavior for typeof inside and outside of strict mode has been considered the likely source of endless "WTFJS" moments. It may be the case that those arguments shouldn't have held sway and that the committee made a mistake here, but every time we revisit the topic (and it happens more than you'd expect), we end up at the same place (nearly no matter who is doing the arguing on each side).

As a practical matter, the 1JS credo has removed much of the appetite for divergent behavior that would have been needed to make this fix in. Modes always bite back, and the question is "how hard". The currently dominant answer is "as little as possible".

primitives also means no wrappers allowed, which is a good practice, generally speaking.

However, primitives does not mean "no Classes allowed" 'cause s:string and s:String could be both valid, and different, one typeof, one instanceof, as well as a:Array rather than just a:object where latter one would be permissive while first one will look for instanceof Array.

The cross frame is nowadays a non-realworld-problem, I don't know any application that uses direct frames access rather than postMessage or JSONP

... in both cases instanceof Array should simply work ... but of course as long as it's possible to access other frames there could be a problem ... in that case, the function that would like to accept Array from any other window can specify a:object and do the [[Class]] check or use Array.isArray to ensure the type after ... create cross frames problems for a type-hint specification when the cross frame is disappeared from basically every library is a non-sense, imho ... who wants to allow such security problematic contract can use his own check, am I wrong?

I don't understand why it's problematic. We're talking about same-origin windows. If there's something malicious on one, it's game over.

As summary, string, number, boolean, undefined, function, null, object, as allowed types would cover already many needed cases, adding Array, Object, GenericScopedConstructor, global.name.spaced.Class on top of types can cover 100% of cases I know.

Last but not least, if all this won't speed up a thing but actually will decrease JS performances, as Alex pointed out at some point, I would vote for then don't no matter what.

There's a tradeoff here: if this is cost that users are already paying for when they write their APIs (either through instanceof/duck-type checks or otherwise), a system provided way to say 'you must be this tall to ride' may be perf-netural, and perhaps even positive to the extent that it reduces boilerplate.

The counter argument is that making this a language feature is likely to dramatically increase the use of such checks (and I agree with this). At that point there's a debate about the marginal utility of each annotation, either as check or as documentation. Dart is showing that you can use these sorts of things a bumpers in development and simply elide them at runtime. It's one extra position on the dial that wasn't well explored before. There are others, and I think we should design with more of them on the table.

# Andrea Giammarchi (7 years ago)

not really, you can have frozen top or stuff like that ... but the point is: why would you use same origin frames and, if you do, why not using postMessage that won't have any instanceof Array problem.

An example/realworld case that could not do it differently? I don't remember one