Proposal to add symbol: "hasInstanceStrict"

# Aleksander Efremov (10 months ago)

It’s attempt to provide intermediate layer for implementation of runtime type checking.

class PrimitiveNumber {
	static [Symbol.hasInstanceStrict](x) {
		if (typeof x !== ’number’) {
			throw new TypeError(‘Invalid type’);
		}
	}
}

function sum(a: PrimitiveNumber, b: PrimitiveNumber) {
	return a + b;
}

const c: PrimitiveNumber = sum(1, 2);

I.e. when appears assignment of variable (const) if then follows : <class> then JS runtime must to call method static [Symbol.hasInstanceStrict](x) and transfer to there assignable value.

# kdex (10 months ago)

Can you give some reasons why this, as opposed to static type checking, is worth pursuing at all?

# Michał Wadas (10 months ago)

Runtime type checking isn't widely deployed for many reasons. Programmable runtime type checking would be even worse because engine can't just throw away function call (only extreme minority of JS function can be proven to be pure).

# Aleksander Efremov (10 months ago)

If data were received from database or isn't trusted sources and you want be sure that they are correct then it's impossible to do with static type checking. And also therefore I don't offer to call function before the real case, I wrote that that check should be executed in runtime, it isn't compilation stage similar to compiling language.

18 февр. 2018 г. 20:56 пользователь "Michał Wadas" <michalwadas at gmail.com> написал:

# Mike Samuel (10 months ago)

Must hasInstanceStrict's parameter remain untyped for a guard to complete or is there a top type with an unguarded hasInstanceStrict that these checks bottom out on?

"has" to my ear sounds like it should return a boolean. Maybe "require."

On Feb 18, 2018 11:30 AM, "Aleksander Efremov" <mr.efrem at gmail.com> wrote:

It’s attempt to provide intermediate layer for implementation of runtime type checking.

class PrimitiveNumber {
        static [Symbol.hasInstanceStrict](x) {
                if (typeof x !== ’number’) {
                        throw new TypeError(‘Invalid type’);
                }
        }
}

function sum(a: PrimitiveNumber, b: PrimitiveNumber) {
        return a + b;
}

const c: PrimitiveNumber = sum(1, 2);

I.e. when appears assignment of variable (const) if then follows : <class> then JS runtime must to call method static [Symbol.hasInstanceStrict](x) and transfer to there assignable value.

# Aleksander Efremov (10 months ago)

Yes, I think that inherited checks it's also good idea. And regarding has I agree. Maybe better to call requireInstance.

18 февр. 2018 г. 22:03 пользователь "Aleksander Efremov" <mr.efrem at gmail.com> написал:

# Aleksander Efremov (10 months ago)

If not all understood me. I offer to call that symbol only in process of execution that code. It isn't attempt to create the compiled language -:).

18 февр. 2018 г. 22:04 пользователь "Aleksander Efremov" <mr.efrem at gmail.com> написал:

# Александр Ефремов (10 months ago)

A reasons for this proposal:

  1. I don’t want to use static type checking (Flow or TypeScript) because on my experience there more a time spend on the describing all types and etc. than it gives favor.
  2. I want to validate API payloads and other sources of data when it’s need. I’m sure that runtime type checking also will be enough popular because currently exists a lot of community libraries which implement such functionality but they all use different approaches: via own babel plugin or need directly call exposed checks functions. And offered by me such intermediate layer can to unify them approaches.
# T.J. Crowder (10 months ago)

On Mon, Feb 19, 2018 at 1:59 PM, Александр Ефремов <mr.efrem at gmail.com>

wrote:

A reasons for this proposal:

  1. I don’t want to use static type checking (Flow or TypeScript) because on my experience there more a time spend on the describing all types and etc. than it gives favor.
  2. I want to validate API payloads and other sources of data when it’s need.

When decorators land, provided they land with a means of decorating functions (either as part of that proposal or as a follow-on), that would do the job, wouldn't it? Using your sum example:

@rttc(PrimitiveNumber, PrimitiveNumber)
const sum = (a, b) => {
    return a + b;
};

...where rttc ("runtime type check") decorates the function such that it does runtime validation of the type of the arguments supplied. (See the issue referenced in the second link above for why I used a function expression rather than declration for sum.)

-- T.J. Crowder

# Mike Samuel (10 months ago)

On Mon, Feb 19, 2018 at 9:25 AM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Mon, Feb 19, 2018 at 1:59 PM, Александр Ефремов <mr.efrem at gmail.com> wrote:

When [decorators][1] land, provided they land with a means of [decorating functions][2] (either as part of that proposal or as a follow-on), that would do the job, wouldn't it? Using your sum example:

@rttc(PrimitiveNumber, PrimitiveNumber)
const sum = (a, b) => {
    return a + b;
};

...where rttc ("runtime type check") decorates the function such that it does runtime validation of the type of the arguments supplied. (See the issue referenced in the second link above for why I used a function expression rather than declration for sum.)

+1 for a single mechanisms that enables not just preconditions, but postconditions.

Decorators could also make it super-easy to do things like deprecation warnings and memoization a la python [1]

[1] wiki.python.org/moin/PythonDecoratorLibrary#Memoize

# Aleksander Efremov (10 months ago)

How do you offer to check a assignment of result of fetch to the variable (const) ? For it also exists decorator?

19 февр. 2018 г. 18:25 пользователь "T.J. Crowder" < tj.crowder at farsightsoftware.com> написал:

On Mon, Feb 19, 2018 at 1:59 PM, Александр Ефремов <mr.efrem at gmail.com>

wrote:

A reasons for this proposal:

  1. I don’t want to use static type checking (Flow or TypeScript) because on my experience there more a time spend on the describing all types and etc. than it gives favor.
  2. I want to validate API payloads and other sources of data when it’s need.

When decorators land, provided they land with a means of decorating functions (either as part of that proposal or as a follow-on), that would do the job, wouldn't it? Using your sum example:

@rttc(PrimitiveNumber, PrimitiveNumber)
const sum = (a, b) => {
    return a + b;
};

...where rttc ("runtime type check") decorates the function such that it does runtime validation of the type of the arguments supplied. (See the issue referenced in the second link above for why I used a function expression rather than declration for sum.)

-- T.J. Crowder

# T.J. Crowder (10 months ago)

On Mon, Feb 19, 2018 at 4:35 PM, Aleksander Efremov <mr.efrem at gmail.com> wrote:

How do you offer to check a assignment of result of fetch to the variable (const) ? For it also exists decorator?

I'm not sure I know what you mean. If you could provide a code example of what you're asking about...?

I don't think there is any concept of a decorator on a local variable/constant that can intercept all assignments to it, no, if that's what you mean. If you literally mean fetch, you could decorate the then callback function, but that wouldn't help with await syntax (which I'd expect to overtake promise syntax fairly quickly).

-- T.J. Crowder

# Aleksander Efremov (10 months ago)

In my first example you can found what I mean. There not only function. Just instead of that function can be black box results which we must check on assignment to const.

19 февр. 2018 г. 20:42 пользователь "T.J. Crowder" < tj.crowder at farsightsoftware.com> написал:

# Mike Samuel (10 months ago)

On Mon, Feb 19, 2018 at 11:50 AM, Aleksander Efremov <mr.efrem at gmail.com>

wrote:

In my first example you can found what I mean. There not only function. Just instead of that function can be black box results which we must check on assignment to const.

Are you referring to the use of PrimitiveNumber in const c: PrimitiveNumber = sum(1, 2); ? When treating sum as a black box, you can't rely on it to check its {pre,post}condiitons, so you need an additional guard on the const initializer?

# Aleksander Efremov (10 months ago)

Yes, that's it.

19 февр. 2018 г. 20:53 пользователь "Mike Samuel" <mikesamuel at gmail.com> написал:

On Mon, Feb 19, 2018 at 11:50 AM, Aleksander Efremov <mr.efrem at gmail.com>

wrote:

In my first example you can found what I mean. There not only function. Just instead of that function can be black box results which we must check on assignment to const.

Are you referring to the use of PrimitiveNumber in const c: PrimitiveNumber = sum(1, 2); ? When treating sum as a black box, you can't rely on it to check its {pre,post}condiitons, so you need an additional guard on the const initializer?

# T.J. Crowder (10 months ago)

On Mon, Feb 19, 2018 at 4:50 PM, Aleksander Efremov <mr.efrem at gmail.com>

wrote:

In my first example you can found what I mean.

Yes, I looked at your first example (and every other example in the thread) before replying. As it had nothing to do with fetch, but you specifically mentioned fetch in your message, I assumed you were asking something about fetch. If you were talking about the const in const c: PrimitiveNumber = sum(1, 2);, why say "fetch"?

-- T.J. Crowder

# Aleksander Efremov (10 months ago)

I gave fetch you just for example that function result which I want to check. Also on the Node.js I wanted be to check results of http module. It just examples of black boxes which impossible to check via decorators how you offered. fetch I assumed to use with await.

19 февр. 2018 г. 20:58 пользователь "T.J. Crowder" < tj.crowder at farsightsoftware.com> написал:

# Aleksander Efremov (10 months ago)

I also mentioned in my first message that I offered to do call that symbol when appears assignmen of variable or const: when appears creating and assignment parameters of function and also when appears assignment of result function to the variable or const. I just left it in the single example. But in real case instead of sum function can be fetch. Or vice versa we want to check in the our library function passed parameter outside.

19 февр. 2018 г. 21:04 пользователь "Aleksander Efremov" <mr.efrem at gmail.com> написал:

# mr.efrem (10 months ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20180220/e5d8db21/attachment

# Aleksander Efremov (10 months ago)

And still one question about function decorators . They will be work if in function parameters uses destructuring?

@rttc(PrimitiveNumber, PrimitiveString, PrimitiveBoolean)
function a (b, { c, d }) {}

20 февр. 2018 г. 0:13 пользователь "mr.efrem" <mr.efrem at gmail.com> написал:

# kai zhu (10 months ago)

On Feb 20, 2018, at 10:05 AM, Aleksander Efremov <mr.efrem at gmail.com> wrote:

And still one question about function decorators . They will be work if in function parameters uses destructuring?

@rttc(PrimitiveNumber, PrimitiveString, PrimitiveBoolean)
function a (b, { c, d }) {}

@aleksander, javascript was not designed to validate functions and class-instances passed around inside a silo'd nodejs-process. its designed to solve UX-problems, which requires validating data passed across multiple javascript-processes (browser <-> server <-> database). you are only painting yourself in a corner, when you’re eventually asked by your employer to apply your nodejs validation-code to sanitize user-inputs from the browser, which you can’t because its not possible (or very difficult) to serialize functions and class-instances over tcp/udp communication.

the employer paying your salary would greatly appreciate it, if you created a validation-system that works not just inside a silo'd nodejs-process, but also in higher-level integrated-systems that includes browsers, storage-engines, and other nodejs-servers talking to each other via tcp/udp.

for these higher-level integrated-systems, your have several serialization-protocols to choose from:

  1. json
  2. xml
  3. protobuf

however, in a javascript-only system, json will always be the obvious choice. i've worked with both xml and protobufs in nodejs, and they are both more trouble than they’re worth. for xml, why deal with extra 3rd-party serializers and parsers you are never sure will be as reliable as builtin JSON.parse and JSON.stringify? for protobufs, the serializers and parsers are even more unreliable (from my experience with node-grpc). they are also slower than JSON.parse and JSON.stringify due to how expensive it is to make function-calls to c++ native-code inside nodejs, and protobuf-data is not human-readable/debuggable.

going with json, there are several validators you can choose from. i'm most familiar with swagger (v2.0), so will provide you with a standalone real-world swagger-solution to your

@rttc(PrimitiveNumber, PrimitiveString, PrimitiveBoolean)
function a (b, { c, d }) {}

validation-problem. (with attached screenshots showing it working in both nodejs and browser)

browser-example from kaizhu256.github.io/node-swgg-github-all/build..beta..travis-ci.org/app

/*
 * validate.js
 *
 * to run code in nodejs, you will need to
 * $ npm install swgg
 */

/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 100,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/

'use strict’;

function aa(myData) {
/*
 * this standalone (browser/nodejs compatible) function will validate myData with the given format
 * {
 *     bb: <number>,
 *     mySubData: {
 *         cc: <string>,
 *         dd: <boolean>
 *     }
 * }
 */
    var myResult, swgg;
    swgg = (typeof window === 'object' && window)
        ? window.swgg
        : require('swgg');
    try {
        swgg.validateBySwaggerSchema({
            data: myData,
            prefix: ['function aa', 'myData'],
            schema: { $ref: '#/definitions/mySchema' },
            swaggerJson: {
                definitions: {
                    mySchema: {
                        properties: {
                            bb: { type: 'number' },
                            mySubData: { $ref: '#/definitions/mySubSchema' }
                        },
                        required: ['bb', 'mySubData']
                    },
                    mySubSchema: {
                        properties: {
                            cc: { type: 'string' },
                            dd: { type: 'boolean' }
                        },
                        required: ['cc', 'dd']
                    }
                }
            }
        });
    } catch (errorCaught) {
        if (typeof window === 'object' && window) {
            console.error(errorCaught.message);
        } else {
            console.error('\u001b[33m' + errorCaught.message + '\u001b[39m');
        }
        return;
    }
    // process myData after vaidation
    myResult = null;
    if (myData.mySubData.dd) {
        myResult = myData.bb + ' ' + myData.mySubData.cc;
    }
    console.log(myResult);
}

// test validaton failed
aa({ bb: 'invalid number' });
aa({ bb: 1234, mySubData: 'invalid object' });
aa({ bb: 1234, mySubData: { cc: 'hello', dd: 'invalid boolean' } });
aa({}); // missing bb
aa({ bb: 1234 }); // missing mySubData
aa({ bb: 1234, mySubData: {} }); // missing mySubData.cc
aa({ bb: 1234, mySubData: { cc: 'hello' } }); // missing mySubData.dd

// test validation passed
aa({ bb: 1234, mySubData: { cc: 'hello', dd: true } });

/* output
error.objectRequired - object function aa["myData"] = {"bb":"invalid number"} must have property "mySubData"
error.itemType - value function aa["myData"]["mySubData"] = "invalid object" is not a valid object
error.itemType - value function aa["myData"]["mySubData"]["dd"] = "invalid boolean" is not a valid boolean
error.objectRequired - object function aa["myData"] = {} must have property "bb"
error.objectRequired - object function aa["myData"] = {"bb":1234} must have property "mySubData"
error.objectRequired - object function aa["myData"]["mySubData"] = {} must have property "cc"
error.objectRequired - object function aa["myData"]["mySubData"] = {"cc":"hello"} must have property "dd"
*/

# T.J. Crowder (10 months ago)

On Tue, Feb 20, 2018 at 8:34 AM, kai zhu <kaizhu256 at gmail.com> wrote:

@aleksander, javascript was not designed to validate functions and class-instances passed around inside a silo'd nodejs-process. its designed to solve UX-problems

Again: This myth is false. It doesn't matter how often you repeat it, it remains false. JavaScript is a general-purpose programming language just like any of several other general-purpose programming languages, your attempts to relegate it to the browser notwithstanding.

-- T.J. Crowder

# Александр Ефремов (10 months ago)

I use ajv epoberezkin/ajv for checking input payloads in the microservices. But it’s enough verbose and also I don’t want to load it in the browser. My offer a more simply and quicker in use.

# kai zhu (10 months ago)

@T.J., no respectable employer would hire an expensive, competent javascript-programmer, if they didn’t have the intention of leveraging him/her to write integration-code interfacing with some kind of web-ui. otherwise, it makes more business-sense to hire cheaper and more-plentiful competent java-programmers.

# T.J. Crowder (10 months ago)

On Tue, Feb 20, 2018 at 8:59 AM, kai zhu <kaizhu256 at gmail.com> wrote:

@T.J., no respectable employer would hire an expensive, competent javascript-programmer, if they didn’t have the intention of leveraging him/her to write integration-code interfacing with some kind of web-ui. otherwise, it makes more business-sense to hire cheaper and more-plentiful competent java-programmers.

I'm not going to get into a back-and-forth with you on this. I'm just going to call you on the "no true Scotsman" rhetorical fallacy and move on.

-- T.J. Crowder

# Александр Ефремов (10 months ago)

And checking payload it was second purpose. First purpose it’s that I don’t want to use third-party static type checking systems (flow, typescript).

# Terence M. Bandoian (10 months ago)

Wasn't JavaScript originally designed for use in the Netscape browser?
Maybe it's more correct to say that it was originally designed for use in web browsers but has been and is being adapted for other purposes.

-Terence Bandoian

# T.J. Crowder (10 months ago)

On Tue, Feb 20, 2018 at 1:15 PM, Terence M. Bandoian <terence at tmbsw.com>

wrote:

Wasn't JavaScript originally designed for use in the Netscape browser? Maybe it's more correct to say that it was originally designed for use in web browsers but has been and is being adapted for other purposes.

The initial version was done in those 10 fateful days in May 1995 (the rush was to stave off competing proposals). Shipped in Netscape Navigator in September 1995, and in Netscape Enterprise Server in December (for server-side scripting). So for three months in 1995, JavaScript was in the wild as a browser-only language; only Brendan Eich or others there at the time can say what the plan for it was.

Regardless how you want to read that, origins more than 22 years ago don't inform what to use modern JavaScript for in 2018, nor how the language should move forward from here.

-- T.J. Crowder

# Mike Samuel (10 months ago)

On Tue, Feb 20, 2018 at 8:37 AM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Tue, Feb 20, 2018 at 1:15 PM, Terence M. Bandoian <terence at tmbsw.com> wrote:

Wasn't JavaScript originally designed for use in the Netscape browser? Maybe it's more correct to say that it was originally designed for use in web browsers but has been and is being adapted for other purposes.

The initial version was done in those 10 fateful days in May 1995 (the rush was to stave off competing proposals). Shipped in Netscape Navigator in September 1995, and in Netscape Enterprise Server in December (for server-side scripting). So for three months in 1995, JavaScript was in the wild as a browser-only language; only Brendan Eich or others there at the time can say what the plan for it was.

Regardless how you want to read that, origins more than 22 years ago don't inform what to use modern JavaScript for in 2018, nor how the language should move forward from here.

In the hopes that quoting relevant docs can help refocus, the TC39 charter www.ecma-international.org/memento/TC39.htm says

""" Scope: Standardization of the general purpose, cross platform, vendor-neutral programming language ECMAScript. ... """

Contrast that with the webapps working group charter which does make explicit mention of clients and the web: """ The scope of the Web Applications Working Group covers the technologies related to developing client-side applications on the Web, ... """

Any discussions about changing the TC39 charter would probably have to involve the larger ECMA organization so it seems off topic to discuss them in a thread devoted to a specific proposal.

# T.J. Crowder (10 months ago)

Excellent point, well made.

-- T.J. Crowder

# Александр Ефремов (10 months ago)

Anyone else has interest to this proposal?

# Mike Samuel (10 months ago)

On Tue, Feb 20, 2018 at 12:33 PM, Александр Ефремов <mr.efrem at gmail.com>

wrote:

Anyone else has interes to this proposal?

I'm probably just going to echo themes that T.J. has dealt with better, but:

Things i like:

  • provides preconditions
  • guards locals

Things I don't like:

  • doesn't deal with postconditions
  • somewhat redundant with annotations
  • adds syntax

It seems that there are two separable issues:

  1. Defining guards
  2. Syntax for specifying guards.

It seems to me that (2) might be doable with annotations for locals, so deploying guards could build on annotations.

Where your proposal shines, is in a definition of a guard. I don't much like the way the definition is tied to classes though. Maybe, for class C {} make C(x) // [[Call]] not [[Construct]] default to (x instanceof this) unless the static property you propose is defined.

That would allow you to use any function type as a value predicate which is the minimum needed for a guard.

Leave sub-types that don't override [hasInstance] from super-types to linters.

If confusion between (new C(x)) and (C(x)) is too much of a hazard, maybe adjust the calling convention for guards so that they always receive a well-known symbol as the first argument, so can switch between acting as a predicate and telling developers how to create class instances.

# T.J. Crowder (10 months ago)

On Tue, Feb 20, 2018 at 6:05 PM, Mike Samuel <mikesamuel at gmail.com> wrote:

I'm probably just going to echo themes that T.J. has dealt with better,

but:

Quite the opposite.

And keying off Mike's excellent summary: I like the idea of providing a means of handling preconditions (and postconditions), of which runtime type checking is one example but only one. I'd just prefer to see it as a general mechanism than type-checking specifically.

I suggest getting deep into the decorators stuff and helping push it forward, possibly into areas where it hasn't previously been headed (such as your let x = sum(y, y) where you want to have runtime type checking on what gets assigned to x -- as far as I know, that isn't even on their radar). Basically that's applying a precondition to the assignment to x (or a postcondition on the call to sum). Which could be interesting. You may or may not get agreement on pushing forward that far, but if you feel strongly about the functionality you're after, I see that as the direction to pursue. (Not that I'm in ANY way any kind of authority on moving things through the process here. Not remotely.)

-- T.J. Crowder

# Mike Samuel (10 months ago)

On Tue, Feb 20, 2018 at 1:20 PM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Tue, Feb 20, 2018 at 6:05 PM, Mike Samuel <mikesamuel at gmail.com> wrote:

I'm probably just going to echo themes that T.J. has dealt with better, but:

Quite the opposite.

And keying off Mike's excellent summary: I like the idea of providing a means of handling preconditions (and postconditions), of which runtime type checking is one example but only one. I'd just prefer to see it as a general mechanism than type-checking specifically.

I suggest getting deep into the decorators stuff and helping push it forward, possibly into areas where it hasn't previously been headed (such as your let x = sum(y, y) where you want to have runtime type checking on what gets assigned to x -- as far as I know, that isn't even on their radar). Basically that's applying a precondition to the assignment to x (or a postcondition on the call to sum). Which could be interesting. You may or may not get agreement on pushing forward that far, but if you feel strongly about the functionality you're after, I see that as the direction to pursue. (Not that I'm in ANY way any kind of authority on moving things through the process here. Not remotely.)

-- T.J. Crowder

One way that decorators (I keep saying annotations) for locals might work is:

@foo const x = initialValue f(x)

desugars to

const x = foo(undefined, initialValue) f(foo(x))

When the decorated local is used as a left-hand side, the use is wrapped in a call to the decorator. When the decorated local is used as a right-hand side, the value assigned is the result of the decorator applied to the previous value and the candidate value.

I think that would be enough to build guards upon.

# Mike Samuel (10 months ago)

On Tue, Feb 20, 2018 at 1:32 PM, Mike Samuel <mikesamuel at gmail.com> wrote:

On Tue, Feb 20, 2018 at 1:20 PM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Tue, Feb 20, 2018 at 6:05 PM, Mike Samuel <mikesamuel at gmail.com> wrote:

I'm probably just going to echo themes that T.J. has dealt with better, but:

Quite the opposite.

And keying off Mike's excellent summary: I like the idea of providing a means of handling preconditions (and postconditions), of which runtime type checking is one example but only one. I'd just prefer to see it as a general mechanism than type-checking specifically.

I suggest getting deep into the decorators stuff and helping push it forward, possibly into areas where it hasn't previously been headed (such as your let x = sum(y, y) where you want to have runtime type checking on what gets assigned to x -- as far as I know, that isn't even on their radar). Basically that's applying a precondition to the assignment to x (or a postcondition on the call to sum). Which could be interesting. You may or may not get agreement on pushing forward that far, but if you feel strongly about the functionality you're after, I see that as the direction to pursue. (Not that I'm in ANY way any kind of authority on moving things through the process here. Not remotely.)

-- T.J. Crowder

One way that decorators (I keep saying annotations) for locals might work is:

@foo const x = initialValue f(x)

desugars to

const x = foo(undefined, initialValue) f(foo(x))

When the decorated local is used as a left-hand side, the use is wrapped in a call to the decorator. When the decorated local is used as a right-hand side, the value assigned is the result of the decorator applied to the previous value and the candidate value.

I think that would be enough to build guards upon.

I cited this thread as a use case for local decorators at tc39/proposal-decorators#51

# Александр Ефремов (10 months ago)

20 февр. 2018 г., в 22:05, Mike Samuel <mikesamuel at gmail.com> написал(а):

On Tue, Feb 20, 2018 at 12:33 PM, Александр Ефремов <mr.efrem at gmail.com <mailto:mr.efrem at gmail.com>> wrote: Anyone else has interes to this proposal?

I'm probably just going to echo themes that T.J. has dealt with better, but:

Things i like:

  • provides preconditions
  • guards locals

Things I don't like:

  • doesn't deal with postconditions
  • somewhat redundant with annotations
  • adds syntax

It seems that there are two separable issues:

  1. Defining guards
  2. Syntax for specifying guards.

It seems to me that (2) might be doable with annotations for locals, so deploying guards could build on annotations.

Where your proposal shines, is in a definition of a guard. I don't much like the way the definition is tied to classes though. Maybe, for class C {} make C(x) // [[Call]] not [[Construct]] default to (x instanceof this) unless the static property you propose is defined.

I took this behavior from Symbol.hasInstance use cases: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance

and how me seems here would be similar approach, because I also wanted to check that assignable value is instance of certain class. But otherwise it must to throw the TypeError exception. And I didn’t understand what you mean about x instanceof this.

That would allow you to use any function type as a value predicate which is the minimum needed for a guard.

Leave sub-types that don't override [hasInstance] from super-types to linters.

Here thought I also didn’t understand.

If confusion between (new C(x)) and (C(x)) is too much of a hazard, maybe adjust the calling convention for guards so that they always receive a well-known symbol as the first argument, so can switch between acting as a predicate and telling developers how to create class instances.

And here -:).

# Александр Ефремов (10 months ago)

20 февр. 2018 г., в 22:32, Mike Samuel <mikesamuel at gmail.com> написал(а):

On Tue, Feb 20, 2018 at 1:20 PM, T.J. Crowder <tj.crowder at farsightsoftware.com <mailto:tj.crowder at farsightsoftware.com>> wrote: On Tue, Feb 20, 2018 at 6:05 PM, Mike Samuel <mikesamuel at gmail.com <mailto:mikesamuel at gmail.com>> wrote:

I'm probably just going to echo themes that T.J. has dealt with better, but:

Quite the opposite.

And keying off Mike's excellent summary: I like the idea of providing a means of handling preconditions (and postconditions), of which runtime type checking is one example but only one. I'd just prefer to see it as a general mechanism than type-checking specifically.

I suggest getting deep into the decorators stuff and helping push it forward, possibly into areas where it hasn't previously been headed (such as your let x = sum(y, y) where you want to have runtime type checking on what gets assigned to x -- as far as I know, that isn't even on their radar). Basically that's applying a precondition to the assignment to x (or a postcondition on the call to sum). Which could be interesting. You may or may not get agreement on pushing forward that far, but if you feel strongly about the functionality you're after, I see that as the direction to pursue. (Not that I'm in ANY way any kind of authority on moving things through the process here. Not remotely.)

-- T.J. Crowder

One way that decorators (I keep saying annotations) for locals might work is:

@foo const x = initialValue f(x)

desugars to

const x = foo(undefined, initialValue) f(foo(x))

When the decorated local is used as a left-hand side, the use is wrapped in a call to the decorator. When the decorated local is used as a right-hand side, the value assigned is the result of the decorator applied to the previous value and the candidate value.

I think that would be enough to build guards upon.

I don’t understand how it will be comfortable to write decorators for checking arguments of every function with different set of arguments:

function a(b: PrimitiveNumber) {}

function a1({ x: PrimitiveBoolean, d: PrimitiveString }) {}

function a2(e: PrimitiveString, { f: PrimitiveNumber, g: PrimitiveString }, j: PrimitiveBoolean) {}

and etc. For every use case I should to create separate decorator? It will also isn’t comfortable. And use decorators for locals for my goal me seems also more verbose and isn’t comfortable.

# Aleksander Efremov (10 months ago)

I offered use syntax which a lot of developers already know and it would be intuitively clear to use it.

21 февр. 2018 г. 9:15 пользователь "Александр Ефремов" <mr.efrem at gmail.com> написал:

# T.J. Crowder (10 months ago)

On Wed, Feb 21, 2018 at 5:15 AM, Александр Ефремов <mr.efrem at gmail.com>

wrote:

I don’t understand how it will be comfortable to write decorators for checking arguments of every function with different set of arguments:

function a(b: PrimitiveNumber) {}

function a1({ x: PrimitiveBoolean, d: PrimitiveString }) {}

function a2(e: PrimitiveString, { f: PrimitiveNumber, g: PrimitiveString

}, j: PrimitiveBoolean) {}

You wouldn't. See my @rttc example earlier, it would be something like:

@rttc(PrimitiveNumber)
function a(b) {}

@rttc({ x: PrimitiveBoolean, d: PrimitiveString })
function a1({ x, d }) {}

@rttc(PrimitiveString, { f: PrimitiveNumber, g: PrimitiveString },
PrimitiveBoolean)
function a2(e, { f, g }, j) {}

Or perhaps the decorations go on the parameters (avoiding the repetition of names in the destructuring above), in which case I probably would have a decorator per typecheck (but the great thing with it being general is you could choose a parameterized decorator instead):

function a(@primitiveNumber b) {}

function a1({ @primitiveBoolean x, @primitiveString d }) {}

function a2(@primitiveString e, { @primitiveNumber f, @primitiveString g },
@primitiveBoolean j) {}

On Wed, Feb 21, 2018 at 5:26 AM, Aleksander Efremov <mr.efrem at gmail.com>

wrote:

I offered use syntax which a lot of developers already know and it would be intuitively clear to use it.

It also conflicts with TypeScript's static types (it looks identical, does something different), so I don't see that being adopted.

-- T.J. Crowder

# Александр Ефремов (10 months ago)

21 февр. 2018 г., в 11:50, T.J. Crowder <tj.crowder at farsightsoftware.com> написал(а):

On Wed, Feb 21, 2018 at 5:15 AM, Александр Ефремов <mr.efrem at gmail.com <mailto:mr.efrem at gmail.com>> wrote:

I don’t understand how it will be comfortable to write decorators for checking arguments of every function with different set of arguments:

function a(b: PrimitiveNumber) {}

function a1({ x: PrimitiveBoolean, d: PrimitiveString }) {}

function a2(e: PrimitiveString, { f: PrimitiveNumber, g: PrimitiveString }, j: PrimitiveBoolean) {}

You wouldn't. See my @rttc example earlier, it would be something like:

@rttc(PrimitiveNumber)
function a(b) {}

@rttc({ x: PrimitiveBoolean, d: PrimitiveString })
function a1({ x, d }) {}

@rttc(PrimitiveString, { f: PrimitiveNumber, g: PrimitiveString }, PrimitiveBoolean)
function a2(e, { f, g }, j) {}

Or perhaps the decorations go on the parameters (avoiding the repetition of names in the destructuring above), in which case I probably would have a decorator per typecheck (but the great thing with it being general is you could choose a parameterized decorator instead):

function a(@primitiveNumber b) {}

function a1({ @primitiveBoolean x, @primitiveString d }) {}

function a2(@primitiveString e, { @primitiveNumber f, @primitiveString g }, @primitiveBoolean j) {}

Yes, the last variant is more comfortable, agree.

On Wed, Feb 21, 2018 at 5:26 AM, Aleksander Efremov <mr.efrem at gmail.com <mailto:mr.efrem at gmail.com>> wrote:

I offered use syntax which a lot of developers already know and it would be intuitively clear to use it.

It also conflicts with TypeScript's static types (it looks identical, does something different), so I don't see that being adopted.

-- T.J. Crowder

For locals could be the same variant:

@primitiveNumber const a = sum(1, 2);

It’s good point!

# Terence M. Bandoian (10 months ago)

Thanks for the clarification.

-Terence Bandoian

# kai zhu (10 months ago)

On 2/20/18, Terence M. Bandoian <terence at tmbsw.com> wrote:

Wasn't JavaScript originally designed for use in the Netscape browser? Maybe it's more correct to say that it was originally designed for use in web browsers but has been and is being adapted for other purposes.

-Terence Bandoian

no, my perspective (which i also feel is the industry sentiment) is that web-browsers and frontend-programming are going to take over the world, and make redundant lots of backend-programming tasks, as they get offloaded to run in browsers (or some kind of webview). learning javascript in and of itself is ultimately not going to save you from redundancy. its learning how to use javascript as a tool to solve ever-increasing browser-related programming-tasks that will.

javascript, just being javascript, will naturally become a dominant language. it doesn't have to copy features from java/c# that are mosty irrelevant to the kinds of programming-tasks done in the browser/webview.

# Terence M. Bandoian (10 months ago)

See Mike Samuel's notes below. TC39 appears to have different goal.

-Terence Bandoian