top | item 7050375

Args.js – Optional and Default parameters for JavaScript

53 points| adam-a | 12 years ago |autographer.github.io | reply

39 comments

order
[+] phase_9|12 years ago|reply
I've seen this style of library come up quite a few times whilst hacking away in JavaScript where developers try to introduce a sense of strict typing (I even wrote a similar one myself when I first moved over from ActionScript). In the end I learned to stop worrying and love the <strike>bomb</strike> duck typing[0].

For me; one of the "joys" of coding JavaScript is the expressiveness that comes with a dynamic languages; should you throw an ArgumentError when your function that expects a number is invoked with a String? Maybe - sure it can help catch problems early and effectively "stop-the-line" in your public API, but then again it will probably end up throwing the classic `TypeError: Object foo has no method 'bar'` for you anyway.

For "public" methods which form part of an API (especially when that API is going to be shared outside of my team) I try to make my functions handle failure early (before they delegate off to the "private" internal methods), even better if the public methods can repair any unexpected usage, ie:

  function convertToHex(value) {
    var result;
    
    if (typeof value !== "number") {
      result = convertToHex(parseInt(value, 10));
    }
    else {
      result = "0x" + value.toString(16);
    }
    
    return result;
  }
Also, with regards to default argument values, I've always felt the "native" JavaScript approach was fairly compact and descriptive when required:

  function doFoo(bar) {
    bar = (bar !== undefined) ? bar : "default_value";
  }

[0] http://en.wikipedia.org/wiki/Duck_typing
[+] simon_renoult|12 years ago|reply
Why using :

    function doFoo(bar) {
      bar = (bar !== undefined) ? bar : "default_value";
    }
Over :

    function doFoo(bar) {
      bar = bar || "default_value";
    }
Coercion avoidance ?
[+] ifuller1|12 years ago|reply
I'm not sure that embracing a languages dynamic nature should get in the way of leveraging libraries to write more readable code. One advantage of using a standard approach (be it a third party library, or something bespoke) is that you could enable / disable the 'type checking' depending on the build environment. I wouldn't be surprised if your existing toolchain isn't already bringing some static inference to your development - are you using jsdoc and an IDE with autocomplete, for example?

Trusting you find Dart, Typescript, et al agreeable you have to concede that some people are working with legacy code and can only make iterative changes to their codebase?

[+] adam-a|12 years ago|reply
For me it was partly about providing type errors, but also very much about providing easy to write and easy to read type testing and sorting. Type testing in javascript can be a bit tough on the eye and this hopefully makes it easy to see what parameter types a function will accept.
[+] nebulous1|12 years ago|reply
Appears to use Function.caller ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... )

"Non-standard This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future."

[+] gnud|12 years ago|reply
It seems like you can avoid using Function.caller by suppling Args.js with the arguments yourself, like

Args([/* argument definition */], arguments);

[+] mmastrac|12 years ago|reply
It might not be on the standards track, but the browser support table at the bottom seems to indicate that this is a de-facto standard.
[+] gosukiwi|12 years ago|reply
Wouldn't sweet.js and a macro make a more eye appealing solution? The idea is nice and all but the syntax... is just so ugly.
[+] acjohnson55|12 years ago|reply
I was thinking the same thing.

That and I'm not understanding from the page how this is used in the first place. Is the `arguments` implicit variable being passed in some place? (EDIT: yes, via `Function.caller`.) Are the argument values accessed through the result of calling `Args`?

For a non-macro implementation of this, it might be interesting to use function decorator syntax instead, to put the argument processing outside the function body entirely. Basically, the argument processor decorator function would take an options array and a target function, which has all possible parameters, explicitly named. The decorator would spit out a new function that invisibly does all of the wrangling of `arguments` and then finally calls the target function. An advantage is that I think this would be the most minimal pure JS solution from a syntax perspective, and it would keep the actual function body uncluttered. A disadvantage is that it could only really be used with function expressions (not declarations).

[+] brandonbloom|12 years ago|reply
More than that, macros would be a static solution, expanding to sensible arguments parsing code at compile time. So much metaprogramming these days is dynamic where you pay excessive interpretive cost to evaluate the little DSL every time the function is called. JavaScript programmers are guilty of this, but not nearly as guilty as Ruby programmers...
[+] jdc0589|12 years ago|reply
Seen lots of these at this point. I still don't really understand their purpose.

Its not hard, and doesn't require much, if any, more code than the config options for libraries like this to just handle your arguments normally.

required arguments get defined in your function signature. You assign optional args to local variables defined within your function body via the arguments object. It's pretty easy.

[+] adam-a|12 years ago|reply
The original motivation was providing a single way to deal with a combination of default arguments, optional arguments and the sort of homebrew polymorphism that a lot of libraries use, where a function takes 4 different types of thing and runs through a bunch type tests before doing anything.

For functions with longer parameter lists this should hopefully be more readable too. It's clear what types can be passed to a function.

Out of interest, what other libraries like this have you seen? I did a quick check myself and couldn't find anything comparable.

[+] ufo|12 years ago|reply
Another good reason to assign everything to a local variable ASAP is that if I leave everything in the args object then jshint can't help me prevent typos when accessing fields from that object.
[+] K0nserv|12 years ago|reply
I experimented with something similar a while ago, however my main focus was strictness and not default and optional parameters. I did end up adding it though.

https://github.com/k0nserv/Strict.js

[+] zephjc|12 years ago|reply
typo here in your readme:

    this.define('isFemale', female, String.Boolean);
should be

    this.define('isFemale', female, Strict.Boolean);
[+] michaelwww|12 years ago|reply
TypeScript works for me and it doesn't require any additional JS code. Granted, it won't do runtime checks.