3

Is it possible to know if a function uses an empty return statement versus simply not using the return keyword?

For example:

function noReturn(){ }
function useReturn(){ return; }

console.log( noReturn() );   // undefined
console.log( useReturn() );  // undefined

I know all about WHEN and WHY one would use an empty return statement, I just want to know if you can tell if return; was used at all versus no return statement.

I'm assuming that its not possible, and thats ok. If there was any cool Function prototype trick I didn't know of, that would be sweet.


Edit: Not trying to solve any particular problem, unless general curiosity is a problem. :)
Sam Eaton
  • 1,795
  • 1
  • 14
  • 19
  • From the outside and without looking at code or hacky stuff like stringifying and parsing the function? No. There's no way to tell. –  Jun 28 '15 at 00:56
  • There is no way to tell as `return` is the same as `return undefined` which is the same as no return (JS will return undefined), check the accepted answer @ http://stackoverflow.com/questions/17337064/does-every-javascript-function-have-to-return-a-value – Aziz Saleh Jun 28 '15 at 00:56
  • I'd recommend specifying a language in your question title and text... Not just as a tag. That said, I don't think so... – openwonk Jun 28 '15 at 00:57
  • 2
    @openwonk: Tag info shouldn't go in the title. –  Jun 28 '15 at 00:57
  • 3
    Whatever problem you (think you) are trying to solve, (most likely) you don't need to solve it like this. – Mihai Stancu Jun 28 '15 at 00:58
  • @squint Thanks, added EDIT: removed it. – Sam Eaton Jun 28 '15 at 00:59
  • 1
    @SamEaton: *Shouldn't*. :-) –  Jun 28 '15 at 01:00
  • 1
    I'm bet you're trying to check if a function exited because of a particular condition check or if it ran "to the end". In which case you are running error handling and exception handling the wrong way. – Mihai Stancu Jun 28 '15 at 01:00
  • I'm not try to solve any problem the wrong way. I'm literally just curious. – Sam Eaton Jun 28 '15 at 01:03
  • 1
    Alright then, I'm all for curiosity on the side of syntax boundaries and reflection capabilities. – Mihai Stancu Jun 28 '15 at 01:11
  • 1
    The answer is, for all practical purposes, **no**. Move on to the next curiosity. This one is literally a waste of time, since it explicitly doesn't matter whether a function has an empty `return` or no `return`. – Pointy Jun 28 '15 at 01:12
  • 1
    One approach is to replace every valid return statement with another return statement that only returns a string. If there is no return statement, or logic flows into function termination, then 'undefined' is seen. Otherwise, the exact return is seen. – Drakes Jun 28 '15 at 03:25

4 Answers4

2

You cannot distinguish return values of these three functions:

function a() { }
function b() { return; }
function c() { return undefined; }

according to JS specification.

c-smile
  • 26,734
  • 7
  • 59
  • 86
1

I think this is a toy problem, but here is a possible approach to this problem. Convert the function to a string, then for all instances of a valid return statement anywhere in the string replace them with confederate return statements. Execute this modified function using eval() and observe what is returned.

For example,

function foo(){ return; }
function bar(){ if(0) return; }

becomes

function foo(){ return 'return;'; }         // "return;"
function bar(){ if(0) return 'return'; }    // undefined

This way whatever path the logic follows in the function, if something is explicitly returned, we can know what form it takes. If nothing is returned, due to design or logic flow, then 'undefined' is returned. Consider the following function:

function inspectReturn(fcn) {
  var str = fcn.toString();

  // Anytime we see a 'return something' we replace it with return 'something'
  str = str.replace(/(\b)return \s*(\S[^\n;}]+)/mg, "$1return '$2'");

  // Anywhere we see a lone 'return' we replace it with return 'return'
  str = str.replace(/(\b)return\s*([\n;}])/mg, "$1return 'return;'$2");

  eval("fcn="+str);
  return fcn();
}

We can then observe the return values from the the below sample functions:

function noReturn(){ }                     // undefined
function useReturn(){ return }             // "return;"
function useReturn2(){ return; }           // "return;"
function useReturn3(){ return true; }      // "true"
function useReturn4(){ if(0) return; }     // undefined
function useReturn5(){ return undefined }  // "undefined "
function useReturn6(){ var _return = " return "; return _return; }  // "_return"

Demo: JSBin


Note: Voice your opinion about how the regex can be improved all you wish. You might be able to break it (and congratulations to you), but there are simple and concrete JavaScript parsing rules for validating return statements, so on such a toy problem it's up to the reader to properly implement them. Also, if something is thrown, then catch blocks exist for that. However, this is a sufficient demo IMHO.

Drakes
  • 23,254
  • 3
  • 51
  • 94
  • This I believe is happening to all, however the "OP" apparently wants if there is a way to do this without converting to strings. – Walter Chapilliquen - wZVanG Jun 28 '15 at 01:06
  • That would be nice. However, since it's a toy problem, this is the path of least resistance. – Drakes Jun 28 '15 at 01:07
  • 1
    @Drakes: It's the path of certain doom. It could fail in multiple ways. Only true way via the string value would be to create a JavaScript parser that can handle the function and everything that can go into one, which is pretty much everything. –  Jun 28 '15 at 01:10
  • Since it's a toy problem, how about native functions? – Mihai Stancu Jun 28 '15 at 01:12
  • This really would be, but the right way would be: `(function useReturn(){ var _return = "return"; return f; }).toString().match(/return\s*(\w*);?\s*}\s*/)` – Walter Chapilliquen - wZVanG Jun 28 '15 at 01:14
  • @wZVanG: I'm certain the examples in the question are just examples. He want's to know if it can be divined from any arbitrary function. That's really no closer to the right way. –  Jun 28 '15 at 01:16
  • The OP commented about this `This wouldn't work. What if the first function contains the string "return" and not the keyword . it would return true.` :P – Walter Chapilliquen - wZVanG Jun 28 '15 at 01:17
1

No, it's not possible to differentiate these:

  • return undefined;
  • return;
  • End of function without returning any value

First, both return undefined; and return; return the same:

12.9 The return Statement

ReturnStatement :

  • return ;
  • return [no LineTerminator here] Expression ;

A return statement causes a function to cease execution and return a value to the caller. If Expression is omitted, the return value is undefined. Otherwise, the return value is the value of Expression.

A ReturnStatement is evaluated as follows:

  1. If the Expression is not present, return (return, undefined, empty).
  2. Let exprRef be the result of evaluating Expression.
  3. Return (return, GetValue(exprRef), empty).

And then, it does not matter if you used return; or nothing, because [[Call]] will return undefined:

13.2.1 [[Call]]

  1. If result.type is throw then throw result.value.
  2. If result.type is return then return result.value.
  3. Otherwise result.type must be normal. Return undefined.
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

Quite apart from knowing that JavaScript does not differentiate these. A way for checking might be:

function noReturn(){ }
function useReturn(){ return; }
function foo(){ 
  var _return = "return";
}
function fooReturn(){ 
  var _return = "return";
  return _return; 
}
function fooReturn2(){ 
  var _return = "return";
  return; 
}


console.log(/return\s*(\w*);?\s*}\s*/.test(noReturn.toString())); //false
console.log(/return\s*(\w*);?\s*}\s*/.test(useReturn.toString())); //true

console.log(/return\s*(\w*);?\s*}\s*/.test(foo.toString())); //false
console.log(/return\s*(\w*);?\s*}\s*/.test(fooReturn.toString())); //true
console.log(/return\s*(\w*);?\s*}\s*/.test(fooReturn2.toString())); //true