JSCert: Certified JavaScript

RHSCupSmall.jpg

webmaster:

Here is a link to the ECMAScript specification. It seems that the return value of the finally block should always be ignored, unless it's "non-normal" - which means an exception, break, return statement or similar.

Some Tests

  1. Source: try{ "try" } finally { "finally" }
    Result:
    • The specification says this should return "try".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally"
    • In IE 10.0.9200.16466 on and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "finally"
  2. Source: while(true) { try{ "try" ; break } finally { "finally" } }
    Result:
    • The specification says this should return "try".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "try"
  3. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{"try" ; break} finally { "finally" } ; x = "done" }
    Result:
    • The specification says this should return "try".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "try"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "try"
  4. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{"try" ; break} finally { "finally" } ; x = "done" } ; x
    Result:
    • The specification says this should return "stop looping".
    • In Firefox 18 and 18.0.2, we see "stop looping".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "stop looping".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "stop looping"
    • In Opera version 12.12.1707, we see "stop looping"
    • In Safari 6.0, we see "stop looping"
  5. Source: while(true) { try{"try"} finally {"finally"; break} }
    Result:
    • The specification says this should return "finally".
    • In Firefox 18 and 18.0.2, we see "finally".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "finally"
  6. Source: while(true) { try{"try"} finally {break} }
    Result:
    • The specification says this should return the empty value.
    • In Firefox 18 and 18.0.2, we see "try".
    • in node.js 0.16.19 and Chromium 23.0.1271.97, we see "try".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "try"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "try"
  7. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{"try" ; break} finally { } ; x = "done" }
    Result:
    • The specification says this should return "try".
    • In Firefox 18 and 18.0.2, we see "try".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "try"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "try"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "try"
  8. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{"try" ; break} finally { if(4){} } ; x = "done" }
    Result:
    • The specification says this should return "try".
    • In Firefox 18 and 18.0.2, we see "try".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "try"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "try"
    • In Opera version 12.12.1707, we see "try"
    • In Safari 6.0, we see "try"
You can see similar results if you throw an exception if you s/try{/try{throw "exception"}catch(e){/ then s/"try"/"catch"/ as follows:
  1. Source: try{throw "exception"}catch(e){ "catch" } finally { "finally" }
    Result:
    • The specification says this should return "catch".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally"
    • In IE 10.0.9200.16466 on and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "finally"
  2. Source: while(true) { try{throw "exception"}catch(e){ "catch" ; break } finally { "finally" } }
    Result:
    • The specification says this should return "catch".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "catch"
  3. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{throw "exception"}catch(e){"catch" ; break} finally { "finally" } ; x = "done" }
    Result:
    • The specification says this should return "catch".
    • In Firefox 18 and 18.0.2, we see "finally"
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "catch"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "catch"
  4. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{throw "exception"}catch(e){"catch" ; break} finally { "finally" } ; x = "done" } ; x
    Result:
    • The specification says this should return "stop looping".
    • In Firefox 18 and 18.0.2, we see "stop looping".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "stop looping".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "stop looping"
    • In Opera version 12.12.1707, we see "stop looping"
    • In Safari 6.0, we see "stop looping"
  5. Source: while(true) { try{throw "exception"}catch(e){"catch"} finally {"finally"; break} }
    Result:
    • The specification says this should return "finally".
    • In Firefox 18 and 18.0.2, we see "finally".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "finally".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "finally"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "finally"
  6. Source: while(true) { try{throw "exception"}catch(e){"catch"} finally {break} }
    Result:
    • The specification says this should return the empty value.
    • In Firefox 18 and 18.0.2, we see "catch".
    • in node.js 0.16.19 and Chromium 23.0.1271.97, we see "catch".
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "catch"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "catch"
  7. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{throw "exception"}catch(e){"catch" ; break} finally { } ; x = "done" }
    Result:
    • The specification says this should return "catch".
    • In Firefox 18 and 18.0.2, we see "catch".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "catch"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "catch"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "catch"
  8. Source: x = "loop" ; while(x=="loop") { x = "stop looping" ; try{throw "exception"}catch(e){"catch" ; break} finally { if(4){} } ; x = "done" }
    Result:
    • The specification says this should return "catch".
    • In Firefox 18 and 18.0.2, we see "catch".
    • In node.js 0.16.19 and Chromium 23.0.1271.97, we see "catch"
    • In IE 10.0.9200.16466 on ARM and Intel64, we see "catch"
    • In Opera version 12.12.1707, we see "catch"
    • In Safari 6.0, we see "catch"

Speculation about implementations

Spidermonkey (Firefox) and IE

Here is what we suspect Spidermonkey and IE are doing, when evaluating a block try { T } finally { F }

  1. Evaluate T and let (Tc,Tr) be the pair of its completion type and return value
  2. Evaluate F and let (Fc,Fr) be the pair of its completion type and return value
  3. If Fc is non-normal and Fr is empty, return (Fc,Tr)
  4. If Fc is non-normal and Fr is non-empty, return (Fc,Fr)
  5. If Fc is normal and Fr is empty, return (Tc,Tr)
  6. If Fc is normal and Fr is non-empty, return (Tc,Fr)
The official bug report of this issue is here.

V8 (node.js and Chromium)

The difference in V8 behaviour between tests 2 and 3 is confusing. Here are some more tests, to explore this:

  1. Source: while(true) { try{ "try" ; break } finally { "finally" } }
    Result:
    • In Chromium 23.0.1271.97, we see "finally"
  2. Source: while(true) { try{ "try" ; break } finally { "finally" } ; y = "done"}
    Result:
    • In Chromium 23.0.1271.97, we see "try"
  3. Source: while(true) { try{ "try" ; break } finally { "finally" } ; if(true){2} else {3} }
    Result:
    • In Chromium 23.0.1271.97, we see "try"
  4. Source: while(true) { try{ "try" ; break } finally { "finally" } ; if(true){2} else {var x = 3} }
    Result:
    • In Chromium 23.0.1271.97, we see "finally"
The official reports of these issues are here and here.