Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #17473 > unrolled thread
| Started by | glathoud <glathoud@yahoo.fr> |
|---|---|
| First post | 2012-12-04 22:00 -0800 |
| Last post | 2012-12-11 00:07 -0800 |
| Articles | 12 — 5 participants |
Back to article view | Back to comp.lang.javascript
Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-04 22:00 -0800
Re: Cheap runtime asserts Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-12-05 20:18 +0100
Re: Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-06 11:19 -0800
Re: Cheap runtime asserts Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2012-12-06 23:41 +0100
Re: Cheap runtime asserts Patricia Shanahan <pats@acm.org> - 2012-12-05 12:00 -0800
Re: Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-06 11:34 -0800
Re: Cheap runtime asserts JJ <jaejunks@glegooilma-swapit.com> - 2012-12-06 07:29 +0000
Re: Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-06 11:40 -0800
Re: Cheap runtime asserts JJ <jaejunks@glegooilma-swapit.com> - 2012-12-07 12:03 +0000
Re: Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-10 23:46 -0800
Re: Cheap runtime asserts Stefan Weiss <krewecherl@gmail.com> - 2012-12-06 23:00 +0100
Re: Cheap runtime asserts glathoud <glathoud@yahoo.fr> - 2012-12-11 00:07 -0800
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-04 22:00 -0800 |
| Subject | Cheap runtime asserts |
| Message-ID | <1892433a-7696-4b03-a94c-0b1f0a984134@googlegroups.com> |
Hello,
To check argument types in functions that are used in many different
places, I have been using this:
function someCoreFunction( domnode, text ) {
// "Cheap runtime assert": fails when `domnode` is not a DOM node.
domnode.childNodes.a;
// Same idea, for a string.
text.substring.a;
// Rest of the function
// ...
}
It helps to catch mistakes early, including during development. I am
*not* advocating to litter the code with thousands such statements,
but in a few strategical places the benefits can exceed the costs.
Hopefully this can help someone. Constructive feedback is welcome.
Guillaume
[toc] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2012-12-05 20:18 +0100 |
| Message-ID | <5675043.5vPKIy9VtG@PointedEars.de> |
| In reply to | #17473 |
glathoud wrote:
^^^^^^^^
Please fix that.
> To check argument types in functions that are used in many different
> places, I have been using this:
>
> function someCoreFunction( domnode, text ) {
>
> // "Cheap runtime assert": fails when `domnode` is not a DOM node.
> domnode.childNodes.a;
>
> // Same idea, for a string.
> text.substring.a;
>
> // Rest of the function
> // ...
>
> }
>
> It helps to catch mistakes early, including during development. I am
> *not* advocating to litter the code with thousands such statements,
> but in a few strategical places the benefits can exceed the costs.
>
> Hopefully this can help someone. Constructive feedback is welcome.
This approach is not going to work; IOW, it is *too* cheap. In order to let
the program continue running, instead of bothering the *user* with runtime
errors and then end prematurely, you will have to catch the TypeError that
is thrown when execution cannot resolve the “a” property of “undefined”.
There is no reasonable, cross-implementation way in which you can tell one
TypeError from another in a program.
Further, you are potentially dealing with host objects here. It is a bad
idea to access host objects' properties without testing them for existence
first. In the worst case the *successful* property access will throw an
exception.
Your experience may not be sufficient to know that a runtime error occurs
then, but it does, and the user will probably see it (for example, Internet
Explorer will display an exclamation mark icon in the status bar left-hand
side). The program will not end cleanly although that could be done, which
is a really bad idea in itself.
The proper and only reliable way is to check passed arguments against the
function requirements, and throw a user-defined exception. Or return a
false-value, if feasible, so that subsequent uses of the return value fail
and the problem can be tracked down to the incorrect method call). See
”typeof” and “isHostMethod”, and “jsx.throwThis()” for that.
HTH
PointedEars
--
Sometimes, what you learn is wrong. If those wrong ideas are close to the
root of the knowledge tree you build on a particular subject, pruning the
bad branches can sometimes cause the whole tree to collapse.
-- Mike Duffy in cljs, <news:Xns9FB6521286DB8invalidcom@94.75.214.39>
[toc] | [prev] | [next] | [standalone]
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-06 11:19 -0800 |
| Message-ID | <87188bbf-3cc7-4926-8154-9a8b7720991e@googlegroups.com> |
| In reply to | #17499 |
The intent is precisely to crash early in cases where the consequences will *surely* lead to a *non-recoverable* crash, that is unacceptable in production.
Goal: fail early rather than later, to reduce or prevent backtracking a silent mistake to its origin, especially - but not only - in asynchronous context.
Certainly not all cases are like this, hence the warning at the end of my original post.
Guillaume
On Wednesday, December 5, 2012 8:18:45 PM UTC+1, Thomas 'PointedEars' Lahn wrote:
> glathoud wrote:
>
> ^^^^^^^^
>
> Please fix that.
>
>
>
> > To check argument types in functions that are used in many different
>
> > places, I have been using this:
>
> >
>
> > function someCoreFunction( domnode, text ) {
>
> >
>
> > // "Cheap runtime assert": fails when `domnode` is not a DOM node.
>
> > domnode.childNodes.a;
>
> >
>
> > // Same idea, for a string.
>
> > text.substring.a;
>
> >
>
> > // Rest of the function
>
> > // ...
>
> >
>
> > }
>
> >
>
> > It helps to catch mistakes early, including during development. I am
>
> > *not* advocating to litter the code with thousands such statements,
>
> > but in a few strategical places the benefits can exceed the costs.
>
> >
>
> > Hopefully this can help someone. Constructive feedback is welcome.
>
>
>
> This approach is not going to work; IOW, it is *too* cheap. In order to let
>
> the program continue running, instead of bothering the *user* with runtime
>
> errors and then end prematurely, you will have to catch the TypeError that
>
> is thrown when execution cannot resolve the “a” property of “undefined”.
>
> There is no reasonable, cross-implementation way in which you can tell one
>
> TypeError from another in a program.
>
>
>
> Further, you are potentially dealing with host objects here. It is a bad
>
> idea to access host objects' properties without testing them for existence
>
> first. In the worst case the *successful* property access will throw an
>
> exception.
>
>
>
> Your experience may not be sufficient to know that a runtime error occurs
>
> then, but it does, and the user will probably see it (for example, Internet
>
> Explorer will display an exclamation mark icon in the status bar left-hand
>
> side). The program will not end cleanly although that could be done, which
>
> is a really bad idea in itself.
>
>
>
> The proper and only reliable way is to check passed arguments against the
>
> function requirements, and throw a user-defined exception. Or return a
>
> false-value, if feasible, so that subsequent uses of the return value fail
>
> and the problem can be tracked down to the incorrect method call). See
>
> ”typeof” and “isHostMethod”, and “jsx.throwThis()” for that.
>
>
>
>
>
> HTH
>
>
>
> PointedEars
>
> --
>
> Sometimes, what you learn is wrong. If those wrong ideas are close to the
>
> root of the knowledge tree you build on a particular subject, pruning the
>
> bad branches can sometimes cause the whole tree to collapse.
>
> -- Mike Duffy in cljs, <news:Xns9FB6521286DB8invalidcom@94.75.214.39>
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2012-12-06 23:41 +0100 |
| Message-ID | <5771137.N9fZnj88gR@PointedEars.de> |
| In reply to | #17533 |
glathoud wrote: > The intent is precisely to crash early in cases where the consequences > will *surely* lead to a *non-recoverable* crash, that is unacceptable in > production. AISB, the approach will crash also in those cases where the consequences of using the asserted feature will _not_ (surely) lead to a non-recoverable crash. Therefore, it is nonsense. Please do not top-post, and do get a real name. -- PointedEars
[toc] | [prev] | [next] | [standalone]
| From | Patricia Shanahan <pats@acm.org> |
|---|---|
| Date | 2012-12-05 12:00 -0800 |
| Message-ID | <jNWdnUip1a1tOiLNnZ2dnUVZ_oadnZ2d@earthlink.com> |
| In reply to | #17473 |
On 12/4/2012 10:00 PM, glathoud wrote:
> Hello,
>
> To check argument types in functions that are used in many different
> places, I have been using this:
>
> function someCoreFunction( domnode, text ) {
>
> // "Cheap runtime assert": fails when `domnode` is not a DOM node.
> domnode.childNodes.a;
...
One problem I have with this is that childNodes seems like a good name
for the children of a node in any tree with an arbitrary fan-out,
regardless of whether it has anything to do with DOM. What advantage do
you see to this compared to checking the type?
Patricia
[toc] | [prev] | [next] | [standalone]
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-06 11:34 -0800 |
| Message-ID | <4eed6d84-a358-4fd7-8e38-4a61730d73d6@googlegroups.com> |
| In reply to | #17501 |
On Wednesday, December 5, 2012 9:00:54 PM UTC+1, Patricia Shanahan wrote:
> On 12/4/2012 10:00 PM, glathoud wrote:
>
> > Hello,
>
> >
>
> > To check argument types in functions that are used in many different
>
> > places, I have been using this:
>
> >
>
> > function someCoreFunction( domnode, text ) {
>
> >
>
> > // "Cheap runtime assert": fails when `domnode` is not a DOM node.
>
> > domnode.childNodes.a;
>
> ...
>
>
>
> One problem I have with this is that childNodes seems like a good name
>
> for the children of a node in any tree with an arbitrary fan-out,
>
> regardless of whether it has anything to do with DOM.
Yes, you are perfectly right. There is absolutely no claim of generality. The goal is not to catch all mistakes, but rather to have a good chance to catch strategic mistakes early with minimal effort/cost, so as to reduce or prevent backtracking the mistake.
Note that you *might* reduce the chance of a worst case false negative using e.g. domnode.getBoundingClientRect.a; but then again that's long to type :)
> What advantage do
>
> you see to this compared to checking the type?
You can target in quite specific way, using a very small amount of code.
In the DOM node case typeof document.createElement('div') may well return 'object',
which is not very specific.
You could use the approach on your own user-defined objects as well, not just on DOM nodes and strings.
[toc] | [prev] | [next] | [standalone]
| From | JJ <jaejunks@glegooilma-swapit.com> |
|---|---|
| Date | 2012-12-06 07:29 +0000 |
| Message-ID | <XnsA121943364577jaejunksglegooilma@0.0.0.23> |
| In reply to | #17473 |
glathoud <glathoud@yahoo.fr> wrote:
> To check argument types in functions that are used in many different
> places, I have been using this:
>
> function someCoreFunction( domnode, text ) {
>
> // "Cheap runtime assert": fails when `domnode` is not a DOM node.
> domnode.childNodes.a;
>
> // Same idea, for a string.
> text.substring.a;
>
> // Rest of the function
> // ...
>
> }
>
> It helps to catch mistakes early, including during development. I am
> *not* advocating to litter the code with thousands such statements,
> but in a few strategical places the benefits can exceed the costs.
>
> Hopefully this can help someone. Constructive feedback is welcome.
>
> Guillaume
Some conditions might still won't cause an exception. For example:
function theFunc(node, txt) {
//the cheap assert (pre-access the property)
node.childNodes[0].data;
//actual code here
if (node.childNodes[0].data === '') {
node.childNodes[0].data = txt;
}
}
theFunc(document.body);
Now, assuming that "document.childNodes[0]" is a HTMLDivElement, the
assert won't cause an exception and the next "if..." statement will be
executed.
[toc] | [prev] | [next] | [standalone]
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-06 11:40 -0800 |
| Message-ID | <cfb82688-a712-4e52-9ec3-ed7f0697320c@googlegroups.com> |
| In reply to | #17513 |
On Thursday, December 6, 2012 8:29:48 AM UTC+1, JJ wrote:
> glathoud <glathoud@yahoo.fr> wrote:
>
> > To check argument types in functions that are used in many different
>
> > places, I have been using this:
>
> >
>
> > function someCoreFunction( domnode, text ) {
>
> >
>
> > // "Cheap runtime assert": fails when `domnode` is not a DOM node.
>
> > domnode.childNodes.a;
>
> >
>
> > // Same idea, for a string.
>
> > text.substring.a;
>
> >
>
> > // Rest of the function
>
> > // ...
>
> >
>
> > }
>
> >
>
> > It helps to catch mistakes early, including during development. I am
>
> > *not* advocating to litter the code with thousands such statements,
>
> > but in a few strategical places the benefits can exceed the costs.
>
> >
>
> > Hopefully this can help someone. Constructive feedback is welcome.
>
> >
>
> > Guillaume
>
>
>
> Some conditions might still won't cause an exception. For example:
>
>
>
> function theFunc(node, txt) {
>
> //the cheap assert (pre-access the property)
>
> node.childNodes[0].data;
>
> //actual code here
>
> if (node.childNodes[0].data === '') {
>
> node.childNodes[0].data = txt;
>
> }
>
> }
>
> theFunc(document.body);
>
>
>
> Now, assuming that "document.childNodes[0]" is a HTMLDivElement, the
>
> assert won't cause an exception and the next "if..." statement will be
>
> executed.
Yes, you are right. The goal is not to catch 100% of the mistakes, but to have a good chance to catch strategic mistakes earls (see my answer to Patricia).
In the case you are describing, you could instead make sure that the data property is defined IF that is what you need:
node.childNodes[0].data.a;
[toc] | [prev] | [next] | [standalone]
| From | JJ <jaejunks@glegooilma-swapit.com> |
|---|---|
| Date | 2012-12-07 12:03 +0000 |
| Message-ID | <XnsA122C28BCCF7Fjaejunksglegooilma@0.0.0.23> |
| In reply to | #17535 |
glathoud <glathoud@yahoo.fr> wrote:
> Yes, you are right. The goal is not to catch 100% of the mistakes, but
> to have a good chance to catch strategic mistakes earls (see my answer
> to Patricia).
>
> In the case you are describing, you could instead make sure that the
> data property is defined IF that is what you need:
>
> node.childNodes[0].data.a;
Ah, I see what you're trying to do. Nice trick.
But how to do it if a parameter of null and non-null are both accepted by
a function? For example, a function to toggle (set/clear) an element's
onclick handler.
function toggleHandler(ele, func) {
ele.onclick.a;
func.a;
ele.onclick = ele.onclick ? null : func;
}
function dummy() {}
//below line would cause an exception.
//it's expected since document doesn't have onclick property
toggleHandler(document, dummy);
//but below line would also cause an exception.
//assuming that document.body.onclick is null before call
toggleHandler(document.body, dummy);
[toc] | [prev] | [next] | [standalone]
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-10 23:46 -0800 |
| Message-ID | <587e3d40-5635-4e67-b7be-b777744f51c1@googlegroups.com> |
| In reply to | #17559 |
On Friday, December 7, 2012 1:03:08 PM UTC+1, JJ wrote:
> But how to do it if a parameter of null and non-null are both accepted by
>
> a function? For example, a function to toggle (set/clear) an element's
>
> onclick handler.
>
>
>
> function toggleHandler(ele, func) {
>
> ele.onclick.a;
>
> func.a;
>
> ele.onclick = ele.onclick ? null : func;
>
> }
In such a case I would probably not use the approach for `func`. Just check `ele`.
I wrote up a bit more about the background leading to the approach: http://glat.info/js.cheap-asserts/
In general it is up to you to decide, for each parameter, whether to "cheap-check", to fully check (like Thomas described) or to leave it as is (e.g. when expecting multiple types and/or using coercion). In the end, this is a matter a cost/benefit analysis.
But in this particular case, you could do this:
function toggleHandler(ele, func) {
ele.onclick.a;
func == null || func.call.a;
ele.onclick = ele.onclick ? null : func;
}
`func == null` covers both `null` and `undefined` cases.
(and using `func.call.a` is a bit more specific to functions than `func.a`).
[toc] | [prev] | [next] | [standalone]
| From | Stefan Weiss <krewecherl@gmail.com> |
|---|---|
| Date | 2012-12-06 23:00 +0100 |
| Message-ID | <k9r4h7$nkc$1@news.albasani.net> |
| In reply to | #17473 |
On 2012-12-05 07:00, glathoud wrote:
> To check argument types in functions that are used in many different
> places, I have been using this:
>
> function someCoreFunction( domnode, text ) {
>
> // "Cheap runtime assert": fails when `domnode` is not a DOM node.
> domnode.childNodes.a;
>
> // Same idea, for a string.
> text.substring.a;
[..]
I see two problems with this approach:
1) This appears to be intended primarily for the development phase. Most
other assert-type runtime checks have a centralized on/off switch, in
order to enable or disable debugging aids like this. Not only is there
no way to globally deactivate them, there is also no easy way to find
them (nothing specific to grep for).
On the other hand, if these statements are intended to remain in the
code after development, the potential error messages that the users will
see (and submit as bugs) are not going to be very helpful: "TypeError:
cannot read property a of undefined" - which of the "asserts" in your
example triggered this?
2) This type of statement will cause linting tools and other code
processors to emit warnings (and rightly so). If you intend to use
something like JSLint or Google's Closure compiler, you'll have to sift
through a lot of irrelevant output in order to find the real warnings.
- stefan
[toc] | [prev] | [next] | [standalone]
| From | glathoud <glathoud@yahoo.fr> |
|---|---|
| Date | 2012-12-11 00:07 -0800 |
| Message-ID | <c93c368b-748d-43a1-9606-46678ba26418@googlegroups.com> |
| In reply to | #17536 |
On Thursday, December 6, 2012 11:00:06 PM UTC+1, Stefan Weiss wrote: > 1) This appears to be intended primarily for the development phase. [...] which of the "asserts" in your example triggered this? > > 2) This type of statement will cause linting tools and other code > processors to emit warnings (and rightly so). [...] you'll have to sift > through a lot of irrelevant output in order to find the real warnings. Yes, good points. If you decide to only check while developing, either delete the "cheap check" lines after developing a few inter-related components to a stable state, or write full checks that are thrown away during build. Without disagreeing with you, I feel uneasy with a code that behaves differently during development and on the live website. This is a matter of choosing a methodology. Concerning the second point, I am questioning whether those warnings are "right". Should the tool limit the programmer, or adapt to his needs? Again, this is a matter of choosing a methodology. Now concerning this: > he potential error messages that the users will > see (and submit as bugs) are not going to be very helpful either: the "users" are programmers, and will most likely set their browser to break on error, and thus immediately see that the required value is e.g. `null` or that they wrongly swapped parameters in a function call. They can then correct their call themselves. Without check, they'd most likely see a consequence further down, which they are much less likely to link to a function call they made - then they are actually less likely to fix it themselves, thus more likely to submit a bug report. Another bug, which you'll have to backtrack to its origin. or: the "users" are not programmers and are anyway NOT going to debug, but rather to submit a bug description focusing on the use case leading to the error, whatever the error is.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.javascript
csiph-web