A Key Computed at Run Time Is Refused

Status: refused by design

a[i] is not FunctionalScript. a[i] is valid JavaScript, and fjs compile refuses it by design: the demo below shows what it prints.

In JavaScript a[i] reads whatever key i names, and the key may name anything the value inherits: a["constructor"], a["__proto__"], a["push"]. The compiler cannot see which, so a bracket read with a key computed at run time is refused. Where the key is an index, a[Number(i)] says so and reads an element; for a key of any type, the entry helper reads an own entry (entries).

The row acc.runtime-key of refused constructs registers the refusal, and property accessor gives its reason.

Examples

/** @type {(a: readonly string[], i: number) => string | undefined} */
const at = (a, i) => a[i];
export default at(["x", "y"], 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: y.

What to Write Instead

Read an element with a[Number(i)], or an own entry with entry(a, i) (spec/property-access/entries), as alternative.f.js does:

/** @type {(a: readonly string[], i: number) => string | undefined} */
const at = (a, i) => a[Number(i)];
export default at(["x", "y"], 1);

It answers y. Number(i) makes the key an index, which reads an element and nothing an array inherits.

A Better Message

Today fjs compile prints computed key is not Number(...) 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:2:24 - error: computed key is not Number(...)
2 | const at = (a, i) => a[i];
  |                        ^

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

sample.mjs:2:24 - error: a key computed at run time is not FunctionalScript: it may name anything the value inherits
2 | const at = (a, i) => a[i];
  |                        ^ JavaScript reads whatever `i` names here, `"constructor"` included
  = help: read an element with `a[Number(i)]`, or an own entry with `entry(a, i)` (spec/property-access/entries):
          const at = (a, i) => a[Number(i)];
  = note: refused by design, see spec/property-access/runtime-keys/README.md

JavaScript source, sample.mjs:

/** @type {(a: readonly string[], i: number) => string | undefined} */
const at = (a, i) => a[i];
export default at(["x", "y"], 1);

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

y

What to write instead

The FunctionalScript spelling, alternative.f.js:

/**
 * The FunctionalScript spelling of [`sample.mjs`](./sample.mjs): the same read, with the key written as the number it is
 * ([`README.md`](./README.md)).
 *
 * @module
 */

/** @type {(a: readonly string[], i: number) => string | undefined} */
const at = (a, i) => a[Number(i)];
export default at(["x", "y"], 1);

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

const $0=($1,$2)=>$1[Number($2)];export default $0(["x","y"],1);

What it answers, its default export:

y

Emergent Testing

Idle. Press Run to start the suite.

  • ./proof.f.mjs