Guards
Peter Michaux
petermichaux at gmail.com
Fri May 27 10:59:40 PDT 2011
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.
> >
> > http://wiki.ecmascript.org/doku.php?id=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 http://wiki.ecmascript.org/doku.php?id=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
More information about the es-discuss
mailing list