proposal-decorators icon indicating copy to clipboard operation
proposal-decorators copied to clipboard

Decorators for assignment expressions? const/let declarations?

Open littledan opened this issue 7 years ago • 5 comments

Previous discussion: https://github.com/tc39/proposal-decorators-previous/issues/32

OK to leave as a follow-on proposal?

littledan avatar Feb 10 '18 23:02 littledan

Use case: runtime guards

This came up at es-discuss "Proposal to add symbol: hasInstanceStrict" that

attempts to provide an intermediate layer for implementing runtime type checking.

to which TJCrowser replied

When [decorators][1] land, provided they land with a means of [decorating functions][2] (either as part of that proposal or as a follow-on), that would do the job, wouldn't it?

The response was that decorators do not allow vetting a value assigned to a local as in

const c: PrimitiveNumber = sum(1, 2);

This issue came up later on:

It seems that there are two separable issues:

  1. Defining guards
  2. Syntax for specifying guards.

It seems to me that (2) might be doable with annotations decorators for locals, so deploying guards could build on annotations decorators.

mikesamuel avatar Feb 20 '18 20:02 mikesamuel

Propose to use such syntax:

@primitiveNumber const c = sum(1, 2);

MrEfrem avatar Feb 21 '18 08:02 MrEfrem

I'd prefer to leave it as a follow on.

bmeck avatar Feb 28 '18 18:02 bmeck

I'd like to suggest changing the const decorators extension to include a get. The way it's currently proposed, it's nothing but syntax sugar for a function call, and is inconsistent with the let variant. Changing a variable declaration from let to const shouldn't change the behaviour of reads (provided the decorator supports read-only operation). Such as the example let @deprecated x = 1, should work the same for const @deprecated y = 1.

With a getter on const, you could do lazy evaluation:

const @lazy maybeNeeded = () => calc(...args);
if (day === "Sunday") { result += f(maybeNeeded); }
if (month === "June") { result += g(maybeNeeded); }
function lazy({ get, set, value }, { kind }) {
  let ready = false;
  switch (kind) {
    case "const": return { get: getLazy, value };
    case "let": return { get: getLazy, set: setLazy, value };
    default: throw Error("bad kind");
  }
  function getLazy() {
    if (!ready) value = get()(), ready = true;
    return value;
  }
  function setLazy(v) {
    set(v);
    ready = false;
  }
}

On another note, can the whole semantics of the { get, set, value } parameter be changed? I don't quite understand the rationale behind allowing the decorator to change the value that's eventually stored in the backing variable. This value travels through decorator chain in the opposite direction than the v in set(v) does, which means you cannot compose decorators that do transformation on assignment.

I would instead suggest { get, set }, where both are single-argument functions returning the transformed value.

// add +1 when reading
function lazyInc({ get, set }) { return { get: v => get(v) + 1, set }; }

// add +1 on initialization and assignment
function eagerInc({ get, set }) { return { get, set: v => set(v + 1) }; }

lightmare avatar Jun 30 '21 14:06 lightmare

it's very sad that no decorators for functions have appeared yet.

Considering that classes themselves are syntactic sugar. They could have been decorators.

If you look at the fact that everything in js comes from an object, functions and classes, it becomes funny. Considering that python also has decorators for functions. It's so funny in general

I think all frameworks dream that these decorators would be added. For example React, which moved from classes to functions a long time ago and Angular with pipe.

And if you look at the fact that everyone is now doing meta-frameworks like next.js, where there is both server and client side.

I think these decorators would be indispensable as - for example - middleware.

MrOxMasTer avatar Aug 03 '24 11:08 MrOxMasTer