-
Notifications
You must be signed in to change notification settings - Fork 995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: function argument validation #773
Conversation
yargs.js
Outdated
@@ -173,41 +174,49 @@ function Yargs (processArgs, cwd, parentRequire) { | |||
} | |||
|
|||
self.boolean = function (keys) { | |||
argsert('<array|string>', [].slice.call(arguments)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.