in With a Computed Key Is Refused

Status: refused by design

k in o is not FunctionalScript. k in o, with a key computed at run time, is valid JavaScript, and fjs compile refuses it by design: the demo below shows what it prints.

"k" in o is in the language (in): a string literal as the key, which the compiler reads and checks against the names a built-in prototype gives a value. A key it cannot read it cannot check, and JavaScript answers such a key from the prototype chain, which FunctionalScript does not have, so any left operand but a string literal is refused at the operator — a name, a number, an operator's result, an in of its own.

The row op.in of refused constructs registers the refusal, and in gives its reason.

Examples

const k = "a";
export default k in { a: 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: true.

What to Write Instead

Ask whether a value has an own entry under a computed key with hasEntry (reading an entry), as alternative.f.js does:

const hasEntry = (a, b) => {
    const x = Object.getOwnPropertyDescriptor(a, b);
    return x?.enumerable === true;
};
const k = "a";
export default hasEntry({ a: 1 }, k);

It answers true, as JavaScript does for the sample: the object owns the entry, and for a key no prototype supplies the two questions agree.

A Better Message

Today fjs compile prints the left operand of in must be a string literal at the operator. 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:18 - error: the left operand of in must be a string literal
2 | export default k in { a: 1 };
  |                  ^

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

sample.mjs:2:18 - error: `in` takes a string literal as its key: a key computed at run time is `hasEntry`'s to test
2 | export default k in { a: 1 };
  |                  ^^ JavaScript evaluates `k` here and asks the prototype chain for it
  = help: ask for an own entry with `hasEntry` (spec/property-access/entries):
          export default hasEntry({ a: 1 }, k);
  = note: refused by design, see spec/operators/in/computed-key/README.md

JavaScript source, sample.mjs:

const k = "a";
export default k in { a: 1 };

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

true

What to write instead

The FunctionalScript spelling, alternative.f.js:

/**
 * The FunctionalScript spelling of [`sample.mjs`](./sample.mjs): the
 * `hasEntry` helper, which tests a key computed at run time
 * ([`README.md`](./README.md)).
 *
 * @module
 */

/** @type {(a: object, b: string) => boolean} */
const hasEntry = (a, b) => {
    const x = Object.getOwnPropertyDescriptor(a, b);
    return x?.enumerable === true;
};
const k = "a";
export default hasEntry({ a: 1 }, k);

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

const $0=($1,$2)=>{const $3=Object.getOwnPropertyDescriptor($1,$2);return $3?.enumerable===true;};export default $0({"a":1},"a");

What it answers, its default export:

true

Emergent Testing

Idle. Press Run to start the suite.

  • ./proof.f.mjs