Closed icylace closed 10 years ago
Nice to hear you like typify!
The instanceof
is used in
instance
functionality, which is triggered by userThunk
)Date
and RegExp
– those probably won't work if Date
and RegExp
aren't sharedI'll fix Date
and RegExp
check shortly (looks like underscore.js is using Object.prototype.toString
trick for them as well. Yet you could workaround it by the same trick as using bacon.js: https://github.com/baconjs/bacon.js/wiki/FAQ#what-if-i-have-multiple-frames-in-my-application
That Bacon workaround is pretty interesting though I don't find it to be ideal.
Thanks for fixing the check for Date and RegExp but the fixes are seemingly not yet reflected in typify.standalone.js.
Since, like you said, instance
is triggered by the user shouldn't that be reason enough to use the {}.toString
technique for that too? I don't understand the reasoning for not doing so.
I was recently made aware that the instanceof
gotcha affects a wider range of scenarios as well. So, wouldn't the interaction between _throws()
and expectedException()
be affected?
The two below are equivalent:
typify.instance(name, cls);
typify.type(name, function (val) {
return val instanceof cls;
});
So the responsibility of using instanceof
is thus on library user.
You might exploit constructor.name
({}.toString
doesn't work for user created "classes"):
It might be what you want, or maybe not, as it is less strict check:
var typify = require("./lib/typify.js");
function make(n) {
return function foo() {};
}
var foo1 = make(1);
var foo2 = make(2);
typify.instance("foo1", foo1);
typify.instance("foo2", foo2);
typify.type("foo1x", function (val) {
return val.constructor.name === foo1.name;
});
typify.type("foo2x", function (val) {
return val.constructor.name === foo2.name;
});
var x = new foo1();
var y = new foo2();
console.log(typify.check("foo1", x)); // true
console.log(typify.check("foo2", x)); // false
console.log(typify.check("foo1", y)); // false
console.log(typify.check("foo2", y)); // true
console.log(typify.check("foo1x", x)); // true
console.log(typify.check("foo2x", x)); // true
console.log(typify.check("foo1x", y)); // true
console.log(typify.check("foo2x", y)); // true
_throws()
and expectedException
are browserify probivided. I guess they work well (and that functionality isn't used or exposed).
Though I could make a standalone build without assert
.
First, thanks for the explanations and updating typify.standalone.js.
I prefer strictness but the case of constructor.name
is pretty interesting. Let's consider your example some more and say we're not able to see any of the code that preceded typify.instance("foo1", foo1);
. Now if we look at those type checks then I think we could come to the conclusion that "foo1" and "foo2" are the result of an abstract factory. I don't believe inheritance would be a possible explanation here. Perhaps aliasing would be? Not completely sure.
In any case I don't know if such an observation would be useful but I find it interesting nonetheless.
I'm not sure what is the right term for this behaviour.
I wanted to show with this example that: If you have multiple frames communicating data to each other, than there aren't fail-proof method to ensure in the first frame that foo
created in second frame is instance of Foo
, if you don't have access to Foo
of the second frame. The best you can get is to make duck-typing checks; constructor name check is one, you could (should?) check more of course.
Yet I don't see this as a problem. You should communicate only raw data (plain objects, arrays, maybe Date's and RegExps which should work now), not "intelligent" objects (as they have references to constructing frame). And validating well-formedness of raw data is what typify is good at.
Yes, fair point. If someone is trying to be too clever with their data their effort could backfire on them.
I've been on a quest to find an ideal runtime type-checking library and yours is the most agreeable I've come across thus far.
I notice that you use
instanceof
quite a few times throughout typify.You noted a weakness of
instanceof
which I was unaware of.Unfortunately, there is another weakness
instanceof
has. When used in a browser environment it will not work correctly when dealing with multiple frames in a window. The MDN docs take note of this. This has been discussed elsewhere as well.Of the solutions to this I've seen, the one used by Mithril is pretty nice. What it does is similar to the following:
Note that
{}.toString
is the same asObject.prototype.toString
which I notice you've used a few times.