2

Let's say we have a function like so:

function foo() {
  // do some work...
  return () => {}; // foo returns a function
}

The client code can use foo in two scenarios:

  1. Use the result of the function
const result = foo();
// some code that uses result...
  1. Ignore the result of the function
foo();

I wonder if the runtime (I don't want to refer to the language itself because it's likely that this is implementation-dependent) will optimize the 1rst case so I don't have to do it myself like this:

function foo(needTheResultValue = false) {
  // do some work...
  if (needTheResultValue) return () => {};
  // nothing is returned if the caller didn't ask for it
}
5
  • 1
    pretty sure it does, but you shouldn't be worried about it as this is unlikely to impact the performance of your app, the code in "2." is completely valid Commented May 25, 2020 at 22:58
  • 1
    Is there some measured cost to creating the return value that you'd like to avoid? Is this code on a hot-path? If not, just return something every time and let the caller choose to ignore the returned value. Commented May 25, 2020 at 22:58
  • the more I think about it, the more I convince myself that doing it manually is a premature optimization in 99% of the cases (when the result if not too expensive to compute) Commented May 25, 2020 at 23:02
  • @rareyesdev Yes, it is. ^^ Commented May 25, 2020 at 23:02
  • Does it matter for your question that the return value is a function object? Commented May 26, 2020 at 12:50

1 Answer 1

2

V8 developer here. The short answer is "it depends, don't worry about it".

In general, V8 (and other engines, as far as I'm aware) optimizes on a per-function basis. So, in your example, if and when foo is optimized, it doesn't know whether its return value will be used or ignored, so it can't optimize it away.

The exception to this is inlining: the optimizing compiler has the ability to inline called functions when the calling function is optimized, e.g. in this example:

function foo() {
  // Do some FOO work...
  return {};
}
function bar() {
  foo();
  // Do some BAR work...
}

When foo is optimized, it will (continue to) return a freshly allocated empty object, regardless of where it's called from. When bar is optimized, the compiler might decide to inline foo, and after that step it sees (its own internal representation of a hypothetical function like):

function bar() {
  // Do some FOO work...
  {};
  // Do some BAR work...
}

And then it can easily drop the unused object allocation in there.

That said, as comments on the question have pointed out, this isn't something you need to worry about. (Unless if you happen to needlessly spend huge amounts of time constructing expensive but unused return values -- but that seems unlikely, because it's a fairly obvious inefficiency, so chances are you wouldn't write such code in the first place.)

In particular, returning some value that you have computed anyway has zero cost compared to returning nothing, because every function always returns something -- if it doesn't have a return statement, then the engine will quietly insert a return undefined; for you. That means function f1() {} and function f2() { return undefined; } will compile to exactly the same code. And if you decided to write something like:

function overly_clever(need_result) {
  let result = do_some_work();
  if (result < 0) handle_error();

  if (need_result) {
    return result;
  } else {
    // Return nothing.
  }
}

Then that function would be ever so slightly (not measurably) slower than if you replaced everything after the empty line with a simple return result, because the "empty" else-branch (with its automatically inserted return undefined;) is no faster than return result, so evaluating the need_result condition is a waste of time.

So, in short: don't worry about it. Write code that makes sense, let the engine take care of optimizing it.

(For completeness: if you do feel a need to do manual optimization work, let it be guided by measuring: profile your app to see where most time is being spent, and measure the effects of any attempted changes to see if they are effective. Don't use microbenchmarks, because they tend to be misleading.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.