Guards

# Peter Michaux (14 years ago)

From: Waldemar <waldemar at google.com>

Date: Thu, May 26, 2011 at 4:22 PM Subject: May 24-26 rough meeting notes

Guard Syntax: Technical aspects ok, but some are worried about the effects of this change on the ECMAScript style.

What aspects of ECMAScript style were cause for concern? Fear of Java?

Cormac's student Tim will work with DaveH to prototype this this summer. Not advanced to Harmony, pending more user experience.

How will more user experience be generated? Through a compiler to ES5?

--

The idea of guards in general seems extremely useful and could potentially save reams and reams of parameter checks that have been manually written in a large-ish project (>20,000 lines) over a

long-ish time period (>2yrs) I'm working on with multiple people. The

project is large enough and long enough that I forget parts of the code. I used to think "just don't send the wrong type of argument to a function" but now that I'm forgetting the code myself and reviewing the code of others daily, I see the large benefit of having the code complain with a clear message when the wrong parameter is sent.

I'm looking at the strawman for guards.

strawman:guards

I don't quite see how they are created.

I understand this part about how they would be used

function f(p :: String, q :: MyType) :: Boolean { ... }

but there is no specific example of how MyType is defined. Is that related to classes at all? I'm hoping it is not related to classes and that it is more akin to some kind of interface definition. Suppose I wanted MyType to be only positive even integers. Perhaps MyType is a can only be a function that takes a single argument that is a string and returns an integer. Perhaps MyType has to be an object with two function properties named alpha and beta.

What about maybe types? Could MyType be defined so that null is not an allowed value? All the manually written not-null parameter checks in Java are an unfortunate result of its type checking system.

Would there be a way to check that too many arguments have been sent to a function?

--

One use case I could see would be using guards in development and then having the minifier strip the guards for production. Then the guard definitions could be stripped as well. I've written the following kind of thing with the intention of stripping code inside the debug block for production.

var double = function (a) { /* DEBUG BEGIN / if (typeof a !== 'number') { throw new Error('a must be a number'); } / DEBUG END / return 2a; };

Peter

# Brendan Eich (14 years ago)

On May 26, 2011, at 9:36 PM, Peter Michaux wrote:

I'm looking at the strawman for guards.

strawman:guards

I don't quite see how they are created.

I understand this part about how they would be used

function f(p :: String, q :: MyType) :: Boolean { ... }

but there is no specific example of how MyType is defined. Is that related to classes at all? I'm hoping it is not related to classes and that it is more akin to some kind of interface definition.

From strawman:guards#creating_guards,

"Optionally we may have an Object.setBrand(guard, brand) method that creates a [[Brand]] internal property on an extensible object guard that doesn’t already have one. It is an error to use Object.setBrand on a guard object that already has a [[Brand]] internal property."

Suppose I wanted MyType to be only positive even integers. Perhaps MyType is a can only be a function that takes a single argument that is a string and returns an integer. Perhaps MyType has to be an object with two function properties named alpha and beta.

Exactly! Some in TC39 want to research contract systems for JS. We have a research intern at Mozilla building such a prototype this summer. The plan was to build a library without syntax, but Waldemar's proposal would give nice syntax (we think -- details to hash out of course) for this work.

What about maybe types? Could MyType be defined so that null is not an allowed value? All the manually written not-null parameter checks in Java are an unfortunate result of its type checking system.

A static type system could perhaps be built on top of Harmony modules. Sam Tobin-Hochstadt's Typed Racket work seems helpful here, although it uses contracts too. This is all good research work.

The point is it is research, not ready to be standardized.

One use case I could see would be using guards in development and then having the minifier strip the guards for production. Then the guard definitions could be stripped as well.

As runtime checkers, you can't erase guards. If you knew a particular use of guards as proposed was a static system that permitted erasure (I have no idea whether this is realistic), then sure. We're a long way from anything like that.

# Peter Michaux (14 years ago)

On Fri, May 27, 2011 at 1:44 AM, Brendan Eich <brendan at mozilla.com> wrote:

On May 26, 2011, at 9:36 PM, Peter Michaux wrote:

I'm looking at the strawman for guards.

strawman:guards

I don't quite see how they are created.

I understand this part about how they would be used

function f(p :: String, q :: MyType) :: Boolean { ... }

but there is no specific example of how MyType is defined. Is that related to classes at all? I'm hoping it is not related to classes and that it is more akin to some kind of interface definition.

From strawman:guards#creating_guards, "Optionally we may have an Object.setBrand(guard, brand) method that creates a [[Brand]] internal property on an extensible object guard that doesn’t already have one. It is an error to use Object.setBrand on a guard object that already has a [[Brand]] internal property."

I did see this when reading the strawman. It seems I missed the following bit

The brand object (the value of the [[Brand]] internal property) can be anything. To be useful, it should be an object with a coerce method.

So would the following code be possible? (I've added Object.hasBrand(o).)

var positiveNumberGuard = {};
Object.setBrand(positiveNumberGuard, {
    coerce: function(specimen) {
        if (typeof specimen !== 'number') {
            throw new Error('must be a number');
        }
        if (specimen <= 0) {
            throw new Error('must be positive');
        }
        return specimen;
    }
});

var nonEmptyStringGuard = {};
Object.setBrand(nonEmptyStringGuard, {
    coerce: function(specimen) {
        if (typeof specimen !== 'string') {
            throw new Error('must be a string');
        }
        if (specimen.length <= 0) {
            throw new Error('must be non-empty');
        }
        return specimen;
    }
});

var identityGuard = {};
Object.setBrand(identityGuard, {
    coerce: function(specimen) {
        return specimen;
    }
});

var guardGuard = {};
Object.setBrand(guardGuard {
    coerce: function(specimen) {
        if (!Object.hasBrand(specimen)) {
            throw new Error('must be a guard');
        }
        return specimen;
    }
});

var makeDoubler = function(guard = identityGuard :: guardGuard) {
    return function(x :: guard) {
        return x + x;
    };
};

var positiveNumberDoubler = makeDoubler(positiveNumberGuard);
positiveNumberDoubler(1); // 2
positiveNumberDoubler("a"); // throws "must be a number"

var nonEmptyStringDoubler = makeDoubler(nonEmptyStringGuard);
nonEmptyStringDoubler(1); // throws "must be a string"
nonEmptyStringDoubler("a"); // "aa"

var doubler = makeDoubler();
doubler(1); // 2
doubler("a"); // "aa"

I'm impressed with the following if this is what would actually be possible...

function(guard = identityGuard :: guardGuard)

What we have to write now in ES3 can be so long to achieve this kind of default value and parameter checking functionality.

--

The spec also has a bit about the return value of coerce.

Call brand.coerce(s). This will either return a value (either s or possibly a coerced version of s) or throw an exception.

So the return value is actually what the parameter is set to before the function body executes in the case of a guarded parameter?

Suppose I wanted MyType to be only positive even integers. Perhaps MyType is a can only be a function that takes a single argument that is a string and returns an integer. Perhaps MyType has to be an object with two function properties named alpha and beta.

Exactly! Some in TC39 want to research contract systems for JS.

This is an alternate proposal to the guards, correct? I don't see anything in the wiki index about contracts.

We have a research intern at Mozilla building such a prototype this summer. The plan was to build a library without syntax, but Waldemar's proposal would give nice syntax (we think -- details to hash out of course) for this work.

I'd be interested in such a library. Is there any more information what it might look like to use it?

I sort of hacked at one myself to do type checks but my work wasn't very compelling.

function foo(a, b) { assertNumber(a, 'some optional message'); assertString(a, 'some optional message'); // body of function };

The throw was coming from the assert function rather than the foo function itself which was not so great.

What about maybe types? Could MyType be defined so that null is not an allowed value? All the manually written not-null parameter checks in Java are an unfortunate result of its type checking system.

A static type system could perhaps be built on top of Harmony modules.

Just in case, I didn't mean to imply a static type system.

Sam Tobin-Hochstadt's Typed Racket work seems helpful here, although it uses contracts too. This is all good research work. The point is it is research, not ready to be standardized.

One use case I could see would be using guards in development and then having the minifier strip the guards for production. Then the guard definitions could be stripped as well.

As runtime checkers, you can't erase guards.

A minifier could, couldn't it?

function foo(a::MyType) {}

would be minified to

function foo(a) {}

Though with the example I gave above of the makeDoubler function this minification strategy would likely fall apart.

Also if the guard can coerce that could be an important part of a function's computation which gives me a bit of an uneasy feeling like before filters do in aspect-oriented programming.

Peter

# Sam Tobin-Hochstadt (14 years ago)

On Fri, May 27, 2011 at 1:59 PM, Peter Michaux <petermichaux at gmail.com> wrote:

A minifier could, couldn't it?

function foo(a::MyType) {}

would be minified to

function foo(a) {}

These are not the same function at all.

# Peter Michaux (14 years ago)

On Fri, May 27, 2011 at 12:55 PM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:

On Fri, May 27, 2011 at 1:59 PM, Peter Michaux <petermichaux at gmail.com> wrote:

A minifier could, couldn't it?

function foo(a::MyType) {}

would be minified to

function foo(a) {}

These are not the same function at all.

Why?

Peter

# Sam Tobin-Hochstadt (14 years ago)

On Fri, May 27, 2011 at 4:03 PM, Peter Michaux <petermichaux at gmail.com> wrote:

On Fri, May 27, 2011 at 12:55 PM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:

On Fri, May 27, 2011 at 1:59 PM, Peter Michaux <petermichaux at gmail.com> wrote:

A minifier could, couldn't it?

function foo(a::MyType) {}

would be minified to

function foo(a) {}

These are not the same function at all.

Why?

Because foo(7) produces a TypeError in one, and |undefined| in the other (assuming that MyType isn't Number).

# Peter Michaux (14 years ago)

On Fri, May 27, 2011 at 1:24 PM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:

On Fri, May 27, 2011 at 4:03 PM, Peter Michaux <petermichaux at gmail.com> wrote:

On Fri, May 27, 2011 at 12:55 PM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:

On Fri, May 27, 2011 at 1:59 PM, Peter Michaux <petermichaux at gmail.com> wrote:

A minifier could, couldn't it?

function foo(a::MyType) {}

would be minified to

function foo(a) {}

These are not the same function at all.

Why?

Because foo(7) produces a TypeError in one, and |undefined| in the other (assuming that MyType isn't Number).

Yes but I was thinking of the use of guards as a debugging/development tool. During development you can verify that foo is never called with bad values. Then during production, those checks do not need to be performed. By removing the debugging checks for production, this would save wire and execution time.

Peter

# John Tamplin (14 years ago)

On Fri, May 27, 2011 at 4:43 PM, Peter Michaux <petermichaux at gmail.com>wrote:

Yes but I was thinking of the use of guards as a debugging/development tool. During development you can verify that foo is never called with bad values. Then during production, those checks do not need to be performed. By removing the debugging checks for production, this would save wire and execution time.

Sure, until a user typed in a value you never tried during development. You can either rely on these for validating arguments, in which case they have to stay, or you can't, in which case you can treat them like asserts.

# Brendan Eich (14 years ago)

On May 27, 2011, at 10:59 AM, Peter Michaux wrote:

I'm impressed with the following if this is what would actually be possible...

function(guard = identityGuard :: guardGuard)

What we have to write now in ES3 can be so long to achieve this kind of default value and parameter checking functionality.

That is the idea.

Notice there's no type system or contract system spec here. This is just syntax plus an extension mechanism for coercing (which can throw).

Call brand.coerce(s). This will either return a value (either s or possibly a coerced version of s) or throw an exception.

So the return value is actually what the parameter is set to before the function body executes in the case of a guarded parameter?

Yes.

Suppose I wanted MyType to be only positive even integers. Perhaps MyType is a can only be a function that takes a single argument that is a string and returns an integer. Perhaps MyType has to be an object with two function properties named alpha and beta.

Exactly! Some in TC39 want to research contract systems for JS.

This is an alternate proposal to the guards, correct? I don't see anything in the wiki index about contracts.

No, the guards proposal is not contracts only, nor is it runtime nominal typing only (see strawman:trademarks which was not promoted), nor is it runtime structural types. It's syntax + a plugin system for "coercion".

We have a research intern at Mozilla building such a prototype this summer. The plan was to build a library without syntax, but Waldemar's proposal would give nice syntax (we think -- details to hash out of course) for this work.

I'd be interested in such a library. Is there any more information what it might look like to use it?

Not yet -- more when the intern starts, I imagine. Dave may know more.

# David Herman (14 years ago)

To a first, approximation, it would look something like this:

http://doc.racket-lang.org/reference/contracts.html

;-)

Seriously, the idea is to create contracts that can check structural properties by wrapping values with proxies that lazily do the checking. The core idea, known as higher-order contracts, was first published by Robby Findler:

http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.11.4081

Cormac's student, Tim Disney, will be joining us for the summer starting in June, and we'll work on building such a library for JS using proxies. We'll also look into building the syntax into Narcissus.