[Arguments Optional] Please explain the Else scope

[Arguments Optional] Please explain the Else scope
0

#1

I’m not understanding the outer Else loop for the Arguments Optional solution. Could someone help explain it?

The outer Else only gets executed if there’s one or less arguments, hence

var c = arguments[0];

What I don’t understand is if there’s only one argument, how does the following return function knows there’s more than one argument and pass it in as arg2? The return statement seems to conflict with the outer if/else condition.

return function(arg2)

arguments[0] would be arg1. How does the code pass in (3) from addTogether(2)(3) as arg2? What happens when you need to call something like addTogether(2)(3)(4)? Do you just change the return statement to return function(arg2, arg3)?

The full solution is below

function addTogether() {
  // Function to check if a number is actually a number
  // and return undefined otherwise.
  var checkNum = function(num) {
    if (typeof num !== 'number') {
      return undefined;
    } else
      return num;
  };

  // Check if we have two parameters, check if they are numbers
  // handle the case where one is not
  // returns the addition.
  if (arguments.length > 1) {
    var a = checkNum(arguments[0]);
    var b = checkNum(arguments[1]);
    if (a === undefined || b === undefined) {
      return undefined;
    } else {
      return a + b;
    }
  } else {
    // If only one parameter was found, returns a new function that expects two
    // Store first argument before entering the new function scope
    var c = arguments[0];

    // Check the number again, must be outside the function to about returning an object
    // instead of undefined.
    if (checkNum(c)) {
      // Return function that expect a second argument.
      return function(arg2) {
        // Check for non-numbers
        if (c === undefined || checkNum(arg2) === undefined) {
          return undefined;
        } else {
          // if numbers then add them.
          return c + arg2;
        }
      };
    }
  }
}

#2

This is a bit tricky but return function(arg2) { ...} means that you are in fact returning a new function that will be executed on the next call.

Let’s try to walk it down step by step.
Let’s take
addTogether(2)(3) as our function call.

To start the system will evaluate addTogether(2)
Since the argument is only one the else statement block is executed and you see that the return result is this function:

return function(arg2) {
        // Check for non-numbers
        if (c === undefined || checkNum(arg2) === undefined) {
          return undefined;
        } else {
          // if numbers then add them.
          return c + arg2;
        }
      };

So at this point I have this function that expect a new, single, argument, take that and add it the previous stored value c.

In synthesis:
addTogether(2)(3)
addTogether(2) ==> [function]
this returned function is instructed to wait for a second valid arguments and return the sum of this plus the first one
==> (2 + 3) return 5

Hopes it makes sense.
You can see a step by step execution here (pythontutor.com):
https://goo.gl/XVokm1


#3

Yes, this is definitely confusing territory. Let me take a whack at it.

Yes, where the hell did arg2 come from. The truth is that it is completely made up. The variable name is completely made up. It could have been elephantPajamas and it would have worked just fine. Don’t believe me? Change it in all 4 places there and see for yourself.

OK, now that we’ve established that, let’s figure out what is going on here.

When you call the function addTogether with addTogether(2)(3), it first sends the first function it sees, addTogether(2) - at this point it doesn’t see the (3), it’s not part of the function call, but is kind of like a function of the addTogether(2) function. It evaluates it as one argument so it goes to your else statement. There it returns an anonymous function.

But that anonymous function needs an argument. Where can it get it? Think of this, remember that that (3) is kind of a function of the addTogether(2) function and the addTogether(2) function is now returning a function? So that (3) gets sent in that anonymous function call. addTogether(2) returns a value (a function) that gets called with 3 as it’s value.

I’m a big fan of putting console.log statements in my code to help figure out what is happening. Try running this:

function addTogether() {
  // Function to check if a number is actually a number
  // and return undefined otherwise.
  var checkNum = function(num) {
    if (typeof num !== 'number') {
      return undefined;
    } else
      return num;
  };
  console.log("\nentering addTogether, args are ...");
  console.log(arguments);
  // Check if we have two parameters, check if they are numbers
  // handle the case where one is not
  // returns the addition.
  if (arguments.length > 1) {
    var a = checkNum(arguments[0]);
    var b = checkNum(arguments[1]);
    if (a === undefined || b === undefined) {
      return undefined;
    } else {
      return a + b;
    }
  } else {
    // If only one parameter was found, returns a new function that expects two
    // Store first argument before entering the new function scope
    var c = arguments[0];

    // Check the number again, must be outside the function to about returning an object
    // instead of undefined.
    if (checkNum(c)) {
      // Return function that expect a second argument.
      return function(elephantPajamas) {
        console.log("\nin anonymous function and elephantPajamas is " + elephantPajamas + " and args are ...");
        console.log(arguments);
        // Check for non-numbers
        if (c === undefined || checkNum(elephantPajamas) === undefined) {
          return undefined;
        } else {
          // if numbers then add them.
          return c + elephantPajamas;
        }
      };
    }
  }
}

console.log("\nAnswer is " + addTogether(2)(3));

Pay really close attention to what is being called when and especially to what the arguments are being seen by each function.

Some of my terminology here may be nonstandard, but this is how I understand it.


#4

This code is pre es2015 era. Please don’t use outdated technology. Here’s updated version:

// jshint esversion:6

function isNaN(x) { return typeof(x) !== "number"; }

function addTogether(...args) {
  if (args.some(isNaN)) {
    return undefined;
  }
  if (args.length === 2) {
    return args.reduce((a, b) => a + b);
  } else {
    const [a] = args;
    return (b) => addTogether(a, b);
  }
}

#5

Thanks. The step by step execution on pythontutor.com really helped illustrate the statements that ran.


#6

Very good explanation. I’m still a little fuzzy, but I’m getting the gist of it.


#7

Well, if it’s still a little fuzzy, then you’re probably on the right track. I’d be more worried if you thought this made perfect sense and was easy to understand. :wink:

JS does some really weird things with functions. This is one of them.