Conversation
yargs.js
Outdated
| } | ||
|
|
||
| self.boolean = function (keys) { | ||
| argsert('<array|string>', [].slice.call(arguments)) |
There was a problem hiding this comment.
Why the [].slice.call(arguments)? This seems horrifically ugly. =D (Uhm, in the nicest way possible.)
Is argsert trying to forEach the args part? Why not change that to a C-style for loop and save yourself this weirdness?
There was a problem hiding this comment.
Ah, no, I see that you're doing the same thing in argsert itself, so this is thankfully unnecessary.
There was a problem hiding this comment.
definitely a bit ugly, but in our discussion in coding it sounded like there's a pretty big performance hit with passing in arguments -- I opted for ugly and fast.
There was a problem hiding this comment.
That doesn't improve the performance. Passing it to slice still requires the object be created.
|
@JaKXz @nexdrew, etc., I believe I've added argument validation for the whole public API surface; making this pull request ready for prime-time ... regarding the ugly |
|
Using arguments that way is exactly the same performance hit for the compiler. |
|
I recommend you read Bluebird's Optimization Killers docs, it goes into great detail. (The only bit that's a little outdated is reassigning, which is only an issue if you don't |
|
@iarna hmmm, I'd rather avoid adding a build step/macro ... is your thinking "might as well just pass arguments, since slice is slow too"? |
|
Look, your api is not requiring that you pass the actual arguments object. As long as you're ok with taking an array as well, it's fine. Just have a caveat in your docs. Most programs will call this once on startup, not in a fast loop. It's probably fine. If you want to avoid passing arguments at all, you could still test for unwanted args by passing function argcert (spec, len) {
var args = new Array(Math.max(0, arguments.length - 2))
for (var i = 2; i < arguments.length; i++) {
args[i - 2] = arguments[i]
}
if (len < args.length) {
// missing arguments!
} else if (len > args.length) {
// extra arguments!
}
}
function myFunction (a, b, c, d) {
argcert(stringDefinition, arguments.length, a, b, c, d)
}You could do the same thing without the loop using a splat: function argcert (spec, len, ...args)But really, that's a probably just less convenient API, and for a dubious performance benefit, so why bother? I'm really academically curious about the optimization differences between |
|
Yeah, basically what @isaacs said. I would write the code such that the args argument can be an array or a arguments object. That is, just do c-style iteration over it. And then document that folks call it like: function (a, b, c) {
argcert(spec, arguments) // when perf doesn't matter
argcert(spec, [a, b, c]) // when it does
}And beyond that, unless you're calling a function (tens/hundreds of) thousands of times it really doesn't matter if it's deopted. Unoptimized v8 is still fast enough, most of the time. |
|
@iarna @isaacs, having discussed this topic with @JaKXz too; and having read the bluebird docs @iarna shared, I think @isaacs' example of:
Is what I'd like to move to; gives me everything I want, isn't too much more messy, and doesn't do something slow just to have a slightly more magic API signature. This 🚲 🏠 taught me something about Node.js performance, which rocks. |
…rmance, opted for a more explicit API
|
declaring 🚲 🏠 painted. |
BREAKING CHANGE: there's a good chance this will throw exceptions for a few folks who are using the API in an unexpected way.
BREAKING CHANGE: there's a good chance this will throw exceptions for a few folks who are using the API in an unexpected way.
Too help folks consuming the yargs API to better understand when they've provided illegal arguments to functions, this pull request introduces an approach to function argument validation.
I think this is a pretty clean API, and would potentially like to release it post-hoc as a library.