A default Before a case Is Refused

Status: refused by design

default is not FunctionalScript. switch (n) { default: … case 1: … } is valid JavaScript, and fjs compile refuses it by design: the demo below shows what it prints.

In a FunctionalScript switch every branch terminates, in return or throw, so where the default stands says nothing about what runs: JavaScript tries every case first wherever the default is written. The language keeps one spelling, the default last, so a reader finds it where it applies (switch).

The row st.switch-default of refused constructs registers the refusal, and switch gives its reason.

Examples

/** @type {(n: number) => string} */
const name = n => {
    switch (n) {
        default: { return "many"; }
        case 1: { return "one"; }
    }
};
export default name(1);

The demo on this page compiles sample.mjs, the module above, with this build's fjs compile, and shows the line it prints and the token it refuses. Below that it shows what JavaScript answers for the same module: one.

What to Write Instead

Move the default after the last case, as alternative.f.js does:

/** @type {(n: number) => string} */
const name = n => {
    switch (n) {
        case 1: { return "one"; }
        default: { return "many"; }
    }
};
export default name(1);

It answers one. The answer is the same, since JavaScript tries the case first in both.

A Better Message

Today fjs compile prints unexpected token at the refused token. The demo proposes what it should print instead: the reason at the same token, what JavaScript does there, and the allowed spelling, the line alternative.f.js writes, as help. The page compiles the alternative too, so the suggestion is one the compiler accepts.

Reference

Demo

Not allowed in FunctionalScript

This is valid JavaScript, and fjs compile refuses it, by design: it is not a FunctionalScript module.

What fjs compile sample.mjs output.js prints:

sample.mjs:4:9 - error: unexpected token
4 |         default: { return "many"; }
  |         ^

What it should print instead, pointing to what FunctionalScript allows (proposed):

sample.mjs:4:9 - error: a `default` before a `case` is not FunctionalScript: the `default` is written last
4 |         default: { return "many"; }
  |         ^^^^^^^ JavaScript still tries `case 1` before this
  = help: move the `default` after the last `case`:
                  default: { return "many"; }
  = note: refused by design, see spec/control-flow/switch/default-position/README.md

JavaScript source, sample.mjs:

/** @type {(n: number) => string} */
const name = n => {
    switch (n) {
        default: { return "many"; }
        case 1: { return "one"; }
    }
};
export default name(1);

What JavaScript answers for the same module, its default export:

one

What to write instead

The FunctionalScript spelling, alternative.f.js:

/**
 * The FunctionalScript spelling of [`sample.mjs`](./sample.mjs): the same `switch`, its `default` last
 * ([`README.md`](./README.md)).
 *
 * @module
 */

/** @type {(n: number) => string} */
const name = n => {
    switch (n) {
        case 1: { return "one"; }
        default: { return "many"; }
    }
};
export default name(1);

What fjs compile alternative.f.js output.js writes:

const $0=($1)=>$1===1?"one":"many";export default $0(1);

What it answers, its default export:

one

Emergent Testing

Idle. Press Run to start the suite.

  • ./proof.f.mjs