A Prototype's Method Is Refused

Status: refused by design

a.hasOwnProperty(k) is not FunctionalScript. a.hasOwnProperty(k) is valid JavaScript, and fjs compile refuses it by design: the demo below shows what it prints.

Calling a method a built-in prototype defines, such as o.hasOwnProperty(k), is refused: the method is found on the prototype chain, which FunctionalScript does not have, and an object can shadow it with an own entry of the same name. The built-ins the language admits are listed one by one, and these are not among them. Whether a value owns an entry is asked with the hasEntry helper (entries).

The row acc.prototype-call of refused constructs registers the refusal, and built-ins gives its reason.

Examples

export default ({ a: 1 }).hasOwnProperty("a");

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 owns an entry with the hasEntry helper (spec/property-access/entries), as alternative.f.js does:

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

It answers true.

A Better Message

Today fjs compile prints prohibited member function 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:1:27 - error: prohibited member function
1 | export default ({ a: 1 }).hasOwnProperty("a");
  |                           ^

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

sample.mjs:1:27 - error: `hasOwnProperty` is a prototype's method: FunctionalScript has no prototype chain to find it on
1 | export default ({ a: 1 }).hasOwnProperty("a");
  |                           ^^^^^^^^^^^^^^ JavaScript calls `Object.prototype.hasOwnProperty` here
  = help: ask whether a value owns an entry with the `hasEntry` helper (spec/property-access/entries):
          export default hasEntry({ a: 1 }, "a");
  = note: refused by design, see spec/property-access/prototype-calls/README.md

JavaScript source, sample.mjs:

export default ({ a: 1 }).hasOwnProperty("a");

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): whether `{ a: 1 }` owns `a`, asked with the `hasEntry` helper
 * ([`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;
};
export default hasEntry({ a: 1 }, "a");

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