Skip to content
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

add _.noop #1497

Merged
merged 1 commit into from
Mar 3, 2014
Merged

add _.noop #1497

merged 1 commit into from
Mar 3, 2014

Conversation

davidchambers
Copy link
Contributor

This is an unassuming function, but I've found myself defining it more often than one might imagine.

An example of a situation in which this function is useful:

f = (x, success = (->), error = (->)) ->
f = (x, success = _.noop, error = _.noop) ->

@jdalton
Copy link
Contributor

jdalton commented Mar 2, 2014

👍 I dig it, I've had it in my implementation for a bit.

@mlanza
Copy link

mlanza commented Mar 2, 2014

The advantage to _.noop over declaring a null function is you can actually check if a given function is a null function. This can't be done with independently declared null function assignments.

@caseywebdev
Copy link
Contributor

👍

@jashkenas
Copy link
Owner

The advantage to _.noop over declaring a null function is you can actually check if a given function is a null function. This can't be done with independently declared null function assignments.

Quite so. But if you're already checking if the function is a noop or not — then why not (in that particular case) simply pass null and check for null instead? Seems gratuitous.

Any other good arguments for this?

@mlanza
Copy link

mlanza commented Mar 3, 2014

It's subjective of course, but I like the consistency of having a thing be what it is intended to be, of having it abide by a single interface. When a function variable is guaranteed to hold a function and not just sometimes a function, I can rely on dealing with it just one way -- invoking it. This follows suit with the premise behind the null object pattern.

How much of programming should really be about side-stepping nulls? I'd rather use practices that allow me to reduce null checking. If we allow a function variable to sometimes be null, then every site where it might be invoked needs a null guard.

In practice I find that guaranteeing an interface (null object, _.noop) is best implemented so that you don't have to know what's actually being done by the object/function, so perhaps that benefit is overstated.

@jashkenas
Copy link
Owner

Your first two paragraphs are quite right — but are also completely add odds with what you said earlier:

The advantage to _.noop over declaring a null function is you can actually check if a given function is a null function.

Yes, it's nice to consistently always have a passed-in function if you're going to blindly call it. But if you're going to explicitly check if it's a null function before (not) calling it, then you've just reinvented the null value, just by a different, and a nonstandard, name.

@mlanza
Copy link

mlanza commented Mar 3, 2014

I retracted the benefit I formerly mentioned in favor of the consistent interface. I am not suggesting "to explicitly check if it's a null function before (not) calling it." I suggested that blindly calling the function is better than checking what it is. Nix my former statement if you like; I think you're paying too much attention to it.

@jashkenas
Copy link
Owner

I suggested that blindly calling the function is better than checking what it is.

And for that, _.noop gives you nothing that an empty function doesn't, except for a bit less memory use...

@jdalton
Copy link
Contributor

jdalton commented Mar 3, 2014

_.noop is a nice convenience. I found myself creating noop in multiple projects that were already using a util lib so it made sense to add. Underscore could even use it internally for part of its _.bind fallback. FWIW jQuery has $.noop too.

@joshuacc
Copy link

joshuacc commented Mar 3, 2014

And for that, _.noop gives you nothing that an empty function doesn't, except for a bit less memory use...

I'd suggest that _.noop also gives you a nice clear name, enhancing the readability of the code.

@jashkenas jashkenas reopened this Mar 3, 2014
jashkenas added a commit that referenced this pull request Mar 3, 2014
@jashkenas jashkenas merged commit e139881 into jashkenas:master Mar 3, 2014
@davidchambers
Copy link
Contributor Author

I'd suggest that _.noop also gives you a nice clear name, enhancing the readability of the code.

I agree. @jashkenas is quite correct that _.noop is not necessary. In many cases Underscore provides a way to express ideas more clearly; ideas which could have been expressed without help from a library.

I'll provide an example. g unfortunately performs side effects and returns a value. We'd like to derive from it a function h which performs the side effects but returns nothing (i.e. undefined). We could write:

function h() {
  g.apply(null, arguments);
}

Note that we were able to achieve this without help from a library. With Underscore, though, we can express the same thought more clearly:

var h = _.compose(function() {}, g);
var h = _.compose(_.constant(void 0), g);
var h = _.compose(_.constant(), g);

We could take this a step further with _.noop:

var h = _.compose(_.noop, g);

One advantage of _.noop is that it provides the canonical empty function. I can imagine projects using a mix of function() {}, _.constant(undefined), _.constant(void 0), and _.constant() to create empty functions. _.noop would remove the need for discussion, as we'd simply reference the empty function.

@davidchambers davidchambers deleted the noop branch March 3, 2014 17:29
@spadgos
Copy link
Contributor

spadgos commented Mar 4, 2014

PR's already merged but I thought I'd also add another reason for having this 'canonical empty function' around. In my project, it's $.noop, but applies the same here. I modified Backbone.Events.on so that if the handler passed in is the noop function, then it short circuits out of the entire operation.

This is handy when a base class provides noop as the default implementation of a method which is then bound. eg:

Foo.prototype.onSomeEvent = _.noop;
Foo.prototype.setup = function () {
  this.on('someEvent', this.onSomeEvent); // effectively does nothing
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants