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

Switch-case optimization #715

Closed
dead-claudia opened this issue May 20, 2015 · 3 comments
Closed

Switch-case optimization #715

dead-claudia opened this issue May 20, 2015 · 3 comments

Comments

@dead-claudia
Copy link

It would be nice if this could better optimize output like the following below:

  • Input:

    var f;
    f = function(x){
      switch (false) {
      case x !== 0:
        return 'foo';
      case x !== 1:
        return 'bar';
      default:
        return 'baz';
      }
    };
  • Output:

    var f;
    
    f = function(r) {
        switch (!1) {
          case 0 !== r:
            return "foo";
    
          case 1 !== r:
            return "bar";
    
          default:
            return "baz";
        }
    };

This is rare in idiomatic JavaScript, but is frequently spit out of compilers. This could easily be made a lot smaller if it's converted into an if-else or ternary:

  • Better:

    var f;
    
    f = function(r) {
        if (0 !== r) {
            return "foo";
        } else if (1 !== r) {
            return "bar";
        } else {
            return "baz";
        }
    };
  • Best: (may already happen as a consequence)

    var f;
    
    f = function(r) {
        return 0 !== r ? "foo" : 1 !== r ? "bar" : "baz";
    };

Any switch (false), switch (true), switch (!0), or switch (!1) could easily benefit from this transformation.

  • Input:

    var f;
    f = function(x){
      switch (false) {
      case x % 2 !== 0:
        return 'foo';
      case !isFooable(x):
        return 'bar';
      default:
        return 'baz';
      }
    };
  • Output:

    var f;
    
    f = function(r) {
        switch (!1) {
          case r % 2 !== 0:
            return "foo";
    
          case !isFooable(r):
            return "bar";
    
          default:
            return "baz";
        }
    };
  • Better:

    var f;
    
    f = function(r) {
        if (r % 2 !== 0) {
            return "foo";
        } else if (isFooable(r)) {
            return "bar";
        } else {
            return "baz";
        }
    };
  • Best:

    var f;
    
    f = function(r) {
        return r % 2 !== 0 ? "foo" : isFooable(r) ? "bar" : "baz";
    };

As an added caveat for this to remain safe, uncoerced results still have to be checked with ===, as per ES spec:

  • Input:

    var f;
    f = function(x){
      switch (true) {
      case x % 2 === 0:
        return 'foo';
      case isFooable(x): // not coerced
        return 'bar';
      default:
        return 'baz';
      }
    };
  • Output:

    var f;
    
    f = function(r) {
        if (r % 2 === 0) {
            return "foo";
        } else if (isFooable(r) === !0) { // required by ES spec
            return "bar";
        } else {
            return "baz";
        }
    };

Also, this should only be applied if the condition is true, false, !0, or !1.

@dead-claudia
Copy link
Author

Bump.

Also, I forgot to mention another required caveat: all cases with bodies must break or return at the end. The last case, or the default block if it exists, may omit it. If there is any branching at the end, all possible outcomes must end.

Examples:

// Good
switch (!1) {
case !cond: foo(); break;
}

switch (!1) {
case !cond: foo(); break;
case x !== y:
}

switch (!1) {
case !cond: foo(); break;
default:
}

switch (!1) {
case !cond: return foo();
}

switch (!1) {
case !cond:
  if (a) foo();
  break;
}

switch (!1) {
case !cond:
  if (a) {
    return foo();
  } else {
    break;
  }
}
// Bad
switch (!1) {
case !cond: foo();
case x !== y:
}

switch (!1) {
case !cond: foo(); break;
case x !== y:
}

switch (!1) {
case !cond: foo();
default:
}

switch (!1) {
case !cond:
  if (a) foo();
case x !== y:
}

switch (!1) {
case !cond:
  if (a) {
    foo();
  } else {
    break;
  }
case x !== y:
}

@dead-claudia
Copy link
Author

@mishoo?

@alexlamsl
Copy link
Collaborator

Most common cases are covered by switches - any improvements can be made through submitting Pull Requests.

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

No branches or pull requests

2 participants