intertype
Advanced tools
Comparing version 2.9.0 to 3.0.0
@@ -130,2 +130,5 @@ (function() { | ||
}); | ||
this.declare('immediate', function(x) { | ||
return !this.isa.promise(x); | ||
}); | ||
//......................................................................................................... | ||
@@ -323,6 +326,2 @@ this.declare('truthy', (x) => { | ||
//......................................................................................................... | ||
this.declare('value', function(x) { | ||
return !this.isa.promise(x); | ||
}); | ||
//......................................................................................................... | ||
this.declare('object', { | ||
@@ -329,0 +328,0 @@ tests: (x) => { |
@@ -124,3 +124,3 @@ (function() { | ||
this.nowait = function(x) { | ||
this.validate.value(x); | ||
this.validate.immediate(x); | ||
return x; | ||
@@ -127,0 +127,0 @@ }; |
@@ -931,46 +931,96 @@ (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["isa.value, nowait"] = function(T, done) { | ||
var error/* ^44452^ */, f/* ^81112^ */, intertype, isa, nowait, r, type_of, types_of, validate, x; | ||
this["isa.immediate, nowait"] = function(T, done) { | ||
var error, intertype, isa, nowait, r, type_of, types_of, validate; | ||
intertype = new Intertype; | ||
({isa, types_of, type_of, validate, nowait} = intertype.export()); | ||
//......................................................................................................... | ||
T.ok(indexOf.call(types_of(new Promise(function() {})), 'value') < 0); | ||
T.ok(indexOf.call(types_of({ | ||
then: function() {} | ||
}), 'value') < 0); | ||
T.ok(indexOf.call(types_of(42), 'value') >= 0); | ||
error = null; | ||
T.eq(isa.value(null), true); | ||
T.eq(isa.value(12.34), true); | ||
T.eq(isa.value(void 0), true); | ||
T.eq(isa.value(new Promise(function() {})), false); | ||
try { | ||
validate.value(x = 42); | ||
T.ok(true); | ||
validate.value(x = void 0); | ||
T.ok(true); | ||
validate.value(x = null); | ||
T.ok(true); | ||
validate.value(x = 1 * '#'); | ||
T.ok(true); | ||
//......................................................................................................... | ||
T.ok(indexOf.call(types_of(new Promise(function() {})), 'immediate') < 0); | ||
} catch (error1) { | ||
error = error1; | ||
throw error; | ||
T.fail('testcase-171615'); | ||
} | ||
try { | ||
validate.value(x = new Promise(function() {})); | ||
T.ok(false); | ||
T.ok(indexOf.call(types_of({ | ||
then: function() {} | ||
}), 'immediate') < 0); | ||
} catch (error1) { | ||
error = error1; | ||
urge("(ok)", CND.red(error.message)); | ||
T.ok(true); | ||
T.fail('testcase-171616'); | ||
} | ||
if (error == null) { | ||
T.ok(false); | ||
try { | ||
T.ok(indexOf.call(types_of(42), 'immediate') >= 0); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171617'); | ||
} | ||
f = function(x) { | ||
return x ** 2; | ||
}; | ||
r = nowait(f(5)); | ||
try { | ||
//......................................................................................................... | ||
T.eq(isa.immediate(null), true); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171618'); | ||
} | ||
try { | ||
T.eq(isa.immediate(12.34), true); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171619'); | ||
} | ||
try { | ||
T.eq(isa.immediate(void 0), true); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171620'); | ||
} | ||
try { | ||
T.eq(isa.immediate(new Promise(function() {})), false); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171621'); | ||
} | ||
try { | ||
//......................................................................................................... | ||
validate.immediate(42); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171622'); | ||
} | ||
try { | ||
validate.immediate(void 0); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171623'); | ||
} | ||
try { | ||
validate.immediate(null); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171624'); | ||
} | ||
try { | ||
validate.immediate(1 * '#'); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171625'); | ||
} | ||
//......................................................................................................... | ||
T.throws(/not a valid immediate/, function() { | ||
var x; | ||
return validate.immediate(x = new Promise(function() {})); | ||
}); | ||
try { | ||
(r = nowait((function(x) { | ||
return x ** 2; | ||
})(5))); | ||
} catch (error1) { | ||
error = error1; | ||
T.fail('testcase-171626'); | ||
} | ||
T.eq(r, 25); | ||
T.throws(/not a valid immediate/, function() { | ||
return r = nowait((function() { | ||
return new Promise(function() {}); | ||
})()); | ||
}); | ||
return done(); | ||
@@ -981,6 +1031,6 @@ }; | ||
if (module.parent == null) { | ||
test(this); | ||
// test @ | ||
test(this["isa.immediate, nowait"]); | ||
} | ||
// test @[ "isa.value, nowait" ] | ||
// test @[ "types_of() includes happy, sad" ] | ||
@@ -987,0 +1037,0 @@ // test @[ "check(): validation with intermediate results (experiment)" ] |
{ | ||
"name": "intertype", | ||
"version": "2.9.0", | ||
"version": "3.0.0", | ||
"description": "A JavaScript typechecker", | ||
@@ -5,0 +5,0 @@ "main": "lib/main.js", |
@@ -18,3 +18,3 @@ | ||
- [Formal Definition of the Type Concept](#formal-definition-of-the-type-concept) | ||
- [`value` and `nowait`](#value-and-nowait) | ||
- [`immediate` and `nowait`](#immediate-and-nowait) | ||
- [To Do](#to-do) | ||
@@ -211,3 +211,4 @@ | ||
Then, the set of all `x` that are of type `t` are those where `t x` returns `true`, and the set of all `x` | ||
that are not of type `t` are those where `t x` returns `false`; this two sets will always be disjunct. | ||
that are not of type `t` are those where `t x` returns `false`; these two sets will always be disjunct | ||
(otherwise `t` cannot be pure, invalidating the premise). | ||
@@ -219,17 +220,69 @@ Two trivial functions are the set of all members of all types, `any = ( x ) -> true`, and the set of values | ||
# `value` and `nowait` | ||
Observe that the above definition implies that *any and all* JS pure functions of arity one that always | ||
return a boolean define a type, even if unintentionally so; for example `is_legal_input = ( x ) -> ( x is 42 | ||
) or ( x is 'foo' )` implicitly defines a weird type with the weird name 'is_legal_input' that has exactly | ||
two members, an integer number and a three-character string. Less weird and more commonly used are such | ||
types that include only a small, enumerable set of values, as in `traffic_light_color = ( x ) -> x in [ | ||
'red', 'amber', 'green', ]`, otherwise known as 'enumerations', or a smallish set defined by pattern | ||
matching, as in `file_sequence_nr = ( x ) -> ( isa.text x ) and ( x.match /^nr[0-9]{3}$/ )?` (which allows | ||
`nr031` but prohibits `nr03x`). | ||
A maybe surprising type is `value` (in the strict sense), which is a type defined to contain all values `x` | ||
for which `isa.promise x` returns `false` (this includes all native promises and all 'thenables'). | ||
> Observe that in the last example, it is imperative to first test for `x` being a `text` before trying to | ||
> use the `String.prototype.match()` method, this to ensure no exception will ever occur. The alternatives | ||
> are clearly inferior: | ||
> | ||
> * One could `try` to call `x.match()` and then `catch` errors and return `false` instead; however, this | ||
> will make arbitrary objects like `{ match: ( -> true ), }` pass the test which is probably not intended. | ||
> | ||
> * It is possible to `String::match.call x, pattern`, but that will throw for values like `null` and | ||
> `undefined` so still needs to be guarded with `try` and `catch`. | ||
> | ||
> As for the `x in [ ... ]` check, such a safeguard is not needed, but observe that `( new String 'abc' ) in | ||
> [ 'abc' ]` gives `false` which probably does indeed do what you wanted (namely, exclude those problematic | ||
> and vexing [boxed (wrapped) | ||
> values](https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript)) | ||
> that have no justification to be used, ever. | ||
The `value` type has been defined as a convenient way to ensure that a given synchronous function call was | ||
actually synchronous, i.e. did not return a promise; this may be done as | ||
That a 'type' 'is' a function of a certain kind is indeed a desirable property. First of all, it makes | ||
deciding whether a given thing is a type (in almost all cases: trivially) testable. Next, it specifies an | ||
unambiguous method how to construct types, and the method of construction is using first principles—unary, | ||
boolean pure functions, about the most elementary kind of callables. Not least, it assures us that **all | ||
functions that are only composed of calls to type definitions and logical operators define a type, too** | ||
(even if some of those happen to be synonymous to existing types or equivalent to trivial types like `any` | ||
or `all`); in particular, this means that **unions (generalizations) of types** according to this definition | ||
are unequivocally types according to this definition, too, as are **intersections (refinements) of types**. | ||
And, of course, some functions that go beyond combining function calls by means of `and`, `or`, `not` can | ||
shown to be materially types in the sense of this definition. Conversely, we can also be sure that any and | ||
all functions that at least for some inputs will call an impure function cannot be said to represent types | ||
(unless they `try`, `catch` and handle possible exceptions and turn them into a boolean). | ||
> As for whether one should encourage or discourage synonymous types—types with multiple names and | ||
> definitions but identical element sets—the policy is that unwarranted duplication is, of course, to be | ||
> avoided, but clarity and specificity are desirable. In other words, when you find yourself writing | ||
> `validate.integer x` a lot in a single module, chances are that you should really declare a custom type | ||
> `declare mytype = ( x ) -> isa.integer x` *even if that at the moment is nothing more than replicating an | ||
> existing definition*. If you find yourself writing things like `validate.positive_integer x; validate.even | ||
> x` then you should almost certainly define a type that checks for `( isa.positive_integer x ) and ( isa. | ||
> even x)`. Also observe that while the body of a type declaration as such are *extensional*—that is, | ||
> stating the material tests a given value must pass in order to conform to a given type—the names and the | ||
> usage of types should tend to be *intentional*, that is, express fitness for a purpose. Thus, one may want | ||
> to separately define, say, `file_count` and `line_count`: while both are counts (zero or a positive | ||
> natural number), they count different things and may, in a software system, be subject to different | ||
> constraints. | ||
# `immediate` and `nowait` | ||
The type `immediate` is defined as the complement of promises, that is, the set of all values `x` for which | ||
`isa.promise x` returns `false` (so neither native promises nor any 'thenables'—objects where `x.then` is a | ||
function). | ||
The `immediate` type has been defined as a convenient way to ensure that a given synchronous function call | ||
was actually synchronous, i.e. did not return a promise; this may be done as | ||
```coffee | ||
validate.value r = my_sync_function 'foo', 'bar', 'baz' | ||
validate.immediate r = my_sync_function 'foo', 'bar', 'baz' | ||
``` | ||
Observe that 'values' in the strict sense do comprise `NaN`, `null`, `undefined`, `false` and anything else | ||
except for promises, so `x?` is distinct from `isa.value x`; therefore, even when `my_sync_function()` | ||
'doesn't return any value' (i.e. returns `undefined`), that is a value in this sense, too. | ||
Observe that immediates do comprise `NaN`, `null`, `undefined`, `false` and anything else | ||
except for promises, so `x?` is distinct from `isa.immediate x`. | ||
@@ -236,0 +289,0 @@ Equivalently and more succinctly, the validation step can be written with `nowait()`: |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
233390
2412
351