13

I'm currently implementing some shims for the ES6 draft. I'm wondering if anyone can tell me what ReturnIfAbrupt means. For instance, my implementation for Number.toInt (which calls internal [[ToInteger]] is as follows:

if (!('toInt' in Number))
    Object.defineProperty(Number, 'toInt', {

        value: function toInt(value) {
            // ECMA-262 Ed. 6, 9-27-12. 9.1.4

            // 1. Let number be the result of calling ToNumber on the input argument.
            var number = Number(value);

            // 2. ReturnIfAbrupt(number).
            // ?

            // 3. If number is NaN, return +0.
            if (number != number) return 0;

            // 4. If number is +0, -0, +Infinity, or -Infinity, return number.
            if (number == 0 || 1 / number == 0) return number;

            // 5. Return the result of computing sign(number) * floor(abs(number)).
            return (n < 0 ? -1 : 1) * Math.floor(Math.abs(number));

        },

        writable: true,
        configurable: true

    });

Step 2 is ReturnIfAbrupt(number). You'll notice I currently have // ? for that step because I'm not sure what to do. What does it mean when it says ReturnIfAbrupt(...)?

I have read the section on ReturnIfAbrupt in the draft, however I am unable to understand what to do for step 2, what to put in place of // ? in the code above.

From my reading, it may be that nothing should be done, and the ReturnIfAbrupt step merely means to let any error which occurred in ToNumber to propagate up, exiting the function. However, that seems overly verbose, as I would think it could go without saying. Also, it doesn't seem to me like ToNumber can even throw an error. Could someone confirm or help me to understand the real meaning?

Nathan Wall
  • 10,530
  • 4
  • 24
  • 47
  • Here's a starting point: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-8.8.4 – Fabrício Matté Oct 21 '12 at 06:33
  • 1
    Yes, I have read that. It doesn't make complete sense to me, but from what I can make out of it, it sounds like there's really nothing for me to do on that step, and that if an error was thrown by `ToNumber` in step 1 that it should be propagated and the function should exit. However, I don't really understand why that would need its own step, as it should be understood. If that is the case, I'd like confirmation. If it's not the case, I need help understanding. – Nathan Wall Oct 21 '12 at 06:38
  • Your interpretation seems right. There may be some details that I'm missing, but the important part would be throwing an exception back in case of error in the type coversion I'd guess. – Fabrício Matté Oct 21 '12 at 06:51

1 Answers1

6

ReturnIfAbrupt is referring to an Abrupt Completion. A completion record contains a type and the value associated with it. A normal completion would be something like an expression's resulting value. A return completion from a function is the usual expected completion aside from a normal completion. Any other completion types are abrupt. That's throw, break, continue.

if (isCompletionRecord(v)) {
  if (isAbruptCompletion(v)) {
    return v;
  } else {
    v = v.value;
  }
}

Implementing it as you are, what it would entail is wrapping the function in a try catch. A thrown value would be an abrupt completion. This isn't something you see at the JS level though, it's for implementing control flow and non-local control transfers at the engine level.

I've implemented much of the ES6 spec in a JS virtual machine that may also help shed some light on it, here's ToInteger: https://github.com/Benvie/continuum/blob/master/lib/continuum.js#L516

function ToInteger(argument){
  if (argument && typeof argument === OBJECT && argument.IsCompletion) {
    if (argument.IsAbruptCompletion) {
      return argument;
    }
    argument = argument.value;
  }
  return ToNumber(argument) | 0;
}
  • 2
    Thanks! So for me, it practically means "do nothing". It seems strange to me. Can `ToNumber` even result in an abrupt completion? It doesn't seem so. – Nathan Wall Oct 21 '12 at 13:46
  • 1
    Also, correct me if I'm wrong, but from my reading of the draft I'm using (9-27-12), I think this `ToInteger` may not be 100% accurate due to the `ToNumber(argument) | 0` line. Wouldn't that always result in a finite number? The draft seems to indicate `ToInteger` can result in infinite values as well. – Nathan Wall Oct 21 '12 at 13:48
  • It means do nothing unless you're receiving a throw. Think of it frmo the angle of "there is no try catch". One way to implement try..catch is to do exactly what the spec does. Return "throws" like normal results, but wrapped as a "ThrownValue" type and always check for it. Most of the time you don't do have to do anything. But if it's the special result then you need to pass it along without modification. To the ToInteger thing, indeed you are right.I sort of roughly some of the operators in on anticipation of a second pass for detail. –  Oct 22 '12 at 04:26
  • Also of note is that the ReturnIfAbrupt is a non-observable implementation detail. The spec describes what should observably happen, but actual implementations can work completely differently. One example would be using continuation passing style and having a second "control" channel that is used to pass special results like throws. In this case you'd never need to bother with a ReturnIfAbrupt check because the special value would never come through the "normal" channel. –  Oct 22 '12 at 04:30