2

preface

This probably has no real implementation but after reading another post on coffeescript's 2 switch usages, I decided to play around with it and found this rather odd issue.

coffeescript

type = 'guidance'

s = switch
  when type is 'guidance'
   'g'
  when type is 'vulnerability'
   'v'
  else
   'foo'

console.log s #g

transpiled javascript

var s, type;

type = 'guidance';

s = (function() {
  switch (false) {
    case type !== 'guidance':
     return 'g';
  case type !== 'vulnerability':
     return 'v';
  default:
     return 'foo';
 }
})();

console.log(s); //g

the conundrum

What I don't get is that the case expressions are being compiled to the opposite value. The Coffeescript when type is 'guidance' should transpile to the following javascript case type === 'guidance' right?

If you use s = switch true then the case expressions are rendered correctly case type === 'guidance'. Regardless of the rendered javaScript case expressions, the result is the same.

Community
  • 1
  • 1
jusopi
  • 6,791
  • 2
  • 33
  • 44
  • Please re-read your question. The code transpiles to the exact thing you say it should transpile to. – Pointy May 27 '15 at 21:18
  • That's a typo from copying and pasting. It has been corrected – jusopi May 27 '15 at 21:22
  • I wouldn't say this is a "conundrum". The transpiled result works and it's just the way coffeescript decided to implement it. – Mulan May 27 '15 at 21:26

2 Answers2

3

I wouldn't call this an issue, because it works as expected :-)

For the reason, I can only guess (maybe there are some comments in the compiler). It is most likely that they needed to cast all of these expressions to boolean values - they want it to work like an if statement, but switch does use the === operator to compare with the given value. So you can't do

switch (true) {
    case 1: …
    case []: …
    case "true": …
}

because none of those would work, while all of them are truthy values. So you can use the double not operator:

switch (true) {
    case !!( 1 ): …
    case !!( [] ): …
    case !!( "true" ): …
}

and any of those expressions would match true. However, you can reduce your code size a bit by moving the outer ! to the other side of the comparision (!true), and get the equivalent

switch (false) {
    case !( 1 ): …
    case !( [] ): …
    case !( "true" ): …
}

You can see this exact pattern in the coffeescript docs. Now, apparently the compiler is clever enough to compose the ! on an == or === expression to != or !==, but this doesn't work for arbitrary expressions.

If you ask me, they just should've compiled this to a series of if elses.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

For whatever reason, the Coffeescript transpiler generates a switch statement to match the explicit value false, not true. Thus, the case expressions are the opposite of what the when clauses say. When the expression in the when clause is true, the generated switch statement will pick that case because it's looking for the opposite condition to be false.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • I can offer no insight into *why* it works that way. – Pointy May 27 '15 at 21:24
  • That's kinda what I'm seeking is the *why*... then again this is all just *talking shop* so it's not really useful code aside from being able to execute different *contextual* return values from the expressions. – jusopi May 27 '15 at 21:26
  • 3
    @jusopi, if you're looking for the *why*, maybe visit `#coffeescript` on http://freenode.net and ask there. – Mulan May 27 '15 at 21:27