Proposing _.default, _.extend's long-lost cousin #106

Closed
TrevorBurnham opened this Issue Jan 25, 2011 · 9 comments

Projects

None yet

3 participants

@TrevorBurnham

Here's a common scenario: Let's say you have a function that takes an options parameter, and there's a default options object defined outside of the function. (Let's also say that you want to modify the options object by merging defaultOptions in, though in this scenario it probably doesn't matter.) You can't just write _.extend options, defaultOptions, because you don't want the defaults to override the given options; and you can't just write options = _.extend defaultOptions, options, because that would modify defaultOptions (and wouldn't actually modify the given options object).

I propose the following method (presented in CoffeeScript for brevity):

# Extend a given object with all the properties in the subsequent objects,
# unless those properties already exist (and are not null) on the given object.

_.default = (obj) ->
  for source in _.rest(arguments)
    obj[key] ?= val for key, val of source
  obj

This is, of course, simply the definition of _.extend with = converted to ?=.

Example usage:

_.default options, userPreferences, siteSettings

would succinctly say "use the given options; if an option isn't specified, defer to the user's preferences; if neither is specified, use the site's settings."

@ryantenney
Contributor

This is currently possible using _.extend by giving it a new object:

options = _.extend({}, defaultOptions, options)
@TrevorBurnham

Yes, and that's what I'm doing now, but there are two problems:

  1. It's much more verbose than _.default options, defaultOptions, and the repetition of options is unfortunate.
  2. It doesn't work if you want to modify the original options, since it creates a new object.

So if you wrote

setDefaults = (options) -> _.extend {}, defaultOptions, options

you would have to call it with the repetitious options = setDefaults options, not the simpler setDefaults options that would be allowed by

setDefaults = (options) -> _.default options, defaultOptions
@jashkenas
Owner

Thanks, Trevor. I grepped through our codebase, and it's certainly a common enough pattern. I've added it to Underscore at 226b7d9.

@ryantenney
Contributor

Problem: default is a reserved word in Safari.

http://jsconsole.com/?var%20_%3D%7B%7D%3B%20_.default%20%3D%20true%3B

@jashkenas
Owner

Yep -- and that's why the patch landed as _.defaults

@ryantenney
Contributor

Never mind... you're apparently way ahead of me on that ;)

@ryantenney
Contributor

Sorry :)

@TrevorBurnham

Delighted to see this implemented. Out of curiosity, what grep pattern(s) did you use?

@jashkenas
Owner

I grepped for "_.extend({}"

@ryantenney ryantenney pushed a commit to ryantenney/underscore that referenced this issue Aug 25, 2011
@jashkenas Adding _.defaults, Issue #106 226b7d9
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment