Coder Social home page Coder Social logo

tc39 / proposal-logical-assignment Goto Github PK

View Code? Open in Web Editor NEW
302.0 60.0 16.0 217 KB

A proposal to combine Logical Operators and Assignment Expressions

Home Page: https://tc39.es/proposal-logical-assignment/

License: MIT License

HTML 100.00%

proposal-logical-assignment's Introduction

proposal-logical-assignment

A proposal to combine Logical Operators and Assignment Expressions:

// "Or Or Equals" (or, the Mallet operator :wink:)
a ||= b;
a || (a = b);

// "And And Equals"
a &&= b;
a && (a = b);

// "QQ Equals"
a ??= b;
a ?? (a = b);

Status

Current Stage: 4

Champions

Motivation

Convenience operators, inspired by Ruby's. We already have a dozen mathematical assignment operators, but we don't have ones for the often used logical operators.

function example(a) {
  // Default `a` to "foo"
  if (!a) {
    a = 'foo';
  }
}

If statements work, but terseness would be nice. Especially when dealing with deep property assignment:

function example(opts) {
  // Ok, but could trigger setter.
  opts.foo = opts.foo ?? 'bar'

  // No setter, but 'feels wrong' to write.
  opts.baz ?? (opts.baz = 'qux');
}

example({ foo: 'foo' })

With this proposal, we get terseness and we don't have to suffer from setter calls:

function example(opts) {
  // Setters are not needlessly called.
  opts.foo ??= 'bar'

  // No repetition of `opts.baz`.
  opts.baz ??= 'qux';
}

example({ foo: 'foo' })

Semantics

The logical assignment operators function a bit differently than their mathematical assignment friends. While math assignment operators always trigger a set operation, logical assignment embraces their short-circuiting semantics to avoid it when possible.

let x = 0;
const obj = {
  get x() {
    return x;
  },
  
  set x(value) {
    console.log('setter called');
    x = value;
  }
};

// This always logs "setter called"
obj.x += 1;
assert.equal(obj.x, 1);

// Logical operators do not call setters unnecessarily
// This will not log.
obj.x ||= 2;
assert.equal(obj.x, 1);

// But setters are called if the operator does not short circuit
// "setter called"
obj.x &&= 3;
assert.equal(obj.x, 3);

In most cases, the fact that the set operation is short-circuited has no observable impact beyond performance. But when it has side effects, it is often desirable to avoid it when appropriate. In the following example, if the .innerHTML setter was triggered uselessly, it could result in the loss of state (such as focus) that is not serialized in HTML:

document.getElementById('previewZone').innerHTML ||= '<i>Nothing to preview</i>';

See discussion of short-circuit semantics in #3. It also highlights differences already present in mathematical assignment operators in code like obj.deep[key++] += 1 vs obj.deep[key] = obj.deep[key++] + 1.

Related

proposal-logical-assignment's People

Contributors

ajayposhak avatar claudepache avatar danielrosenwasser avatar dnalborczyk avatar hemanth avatar jridgewell avatar keithamus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proposal-logical-assignment's Issues

Editorial nit: notes are incorrect

The current spec text includes new NOTEs (x, x, x) for the runtime semantics for the new operators. These notes are copied from the existing ones in that section.

These notes are both nonsensical and incorrect. Nonsensical because they refer to the "first" and "second" algorithm, which only makes sense when the are applied to the whole block. Incorrect because, if they are applied to the new productions, they imply that (e.g.) a.b ||= c would be a runtime error in strict mode when a's b property is non-writable even if its existing value is truthy, which is not the case (given the short-circuiting semantics).

Duplication of Note in Evaluation

In the Evaluation clause, the existing note is mostly-duplicated 5 times (twice for the existing algorithms and 3 times for the new ones). I think it would be better to retain just one note and reword it to apply to all 5 algorithms. (E.g., don't refer to specific step numbers, just refer to the invocation of PutValue that occurs in each algorithm.)

Better examples?

Hi,

@DanielRosenwasser suggested I open an issue here to discuss better examples.

https://twitter.com/drosenwasser/status/1245995703559532544

Currently exemples feels a bit bad to me, because they show potentially dangerous side-effectful functions

image

Here it's not harmful because the example({ foo: 'foo' }) is passed a new option object everytime, but with example(constantObject) and having the constantObject being shared could be very dangerous, as it could somehow override default option values or things like that.


I don't have a good example to suggest.

Could people that want the feature can come with beter real world code where this new proposal would actually improve the program.

I'm willing to get convinced by this proposal, and wanted to check examples for that, but it didn't really help so far (somehow, related to #2)

Short-circuiting concerns

(raised by @bakkot in the meeting today)

Currently, every assignment combo operator in JS can be described as a = a <op> b being equivalent to a <op>= b.

Including the short-circuiting semantics would make a = a <op> b equivalent to if (a) { a = a <op> b; }, which is a very large inconsistency.

The argument that "Ruby and CoffeeScript have these semantics" imo does not hold its weight compared to "it would be inconsistent with the rest of JS".

Is this worth the syntax complexity?

Logical operators in JavaScript have unexpected behavior (short-circuiting) compared to other languages that return a boolean. Given the long list of proposed syntax additions competing for the complexity budget, is it worth spending it on yet another way to surface this somewhat odd behavior? My feeling is no, but I would like to hear more from other reviewers.

(This was the general feeling that came out of a company-internal discussion between a bunch of us reviewing forthcoming proposals.)

Confusing behavior relative to existing assigment operators

Because the existing assignment operators behave like so:

x += y;
x = x + y;

x -= y;
x = x - y;

// and so on

I would expect the proposed operators to behave in a similar way:

a ||= b;
a = a || b;

a &&= b;
a = a && b;

a ??= b;
a = a ?? b;

I am making no comment on the usefulness of either approach, just that I find the meaning of the operators as proposed to be confusing in light of the behavior of the existing assignment operators.

Property assignment operator

Not sure if here is the right place to mention this, but could this proposal include a property assignment operator such as .= that would assign the value of an object using the name of the variable as the key for the property to update:
given

let objectWithProperty = { property: 'originalValue' }

you could

let property = 'newValue'
objectWithProperty .= property
console.log(objectWithProperty.property) // newValue

Use in destructuring default assignments

Is it feasible for this to be used as part of object destructuring assignments?

const foo = {
  bar: null
}

const {
  bar ??= 'default',
} = foo;

bar === 'default;
// => true

introduce only ??=

Thanks for this proposal.

Anecdotally, I have experience with CoffeeScript, which has all the flavors of logical assignment operator.

I don't think I ever used &&=, and I don't recall seeing it used often.

On the other hand, ??= (which is spelled ?= in CoffeeScript) was commonly useful, and does seem to me (if we're taking votes) worth the complexity it would add to JavaScript.

The other point I want to make is that I recall seeing ||= used often, but it usually seemed like ?= would have been a slightly better choice in most of those cases. I got the sense that ||= was used due to familiarity with the javascript idiom of using || as a default operator, and the programmer just didn't know about ?=.

Have we considered just adding ??= and not the others? You could argue for consistency, but it's my opinion that &&= is not very useful, and that ||= is an attractive nuisance, which people will reach for reflexively and will use to write code that is in some cases incorrect.

There is quite a lot of JS code out there containing subtle bugs caused by treating || as the default operator, and don't the same caveats apply to ||= as apply to using || as a default operator?

Optional assignment

See here for discussion on the mailing list.

Copying most of my original post for brevity:

My thought was to have the following:
this.foo ?= params?.foo;
which can be desugared to
if (($ref = params?.foo) !== undefined) { this.foo = $ref; }

I would strictly check for undefined, rather than nullish, as anything other than undefined would indicate that a value is present that can be set. If no value is present (such as a missing key on an object), nothing would be set. A reference must be used for the general case, as the object
being assigned (the RHS) could be a function or getter with side-effects.

Not sure if it should be ?= or =?, as it would look somewhat odd (IMO) for things like ?+= or +=?.

After looking at some prior discussion regarding ??, my original thought could be expanded to nullish, not just undefined, but that wouldn't make as much sense to me, given the difference between the two.

Destructing

Hi, i have a question regarding destructing, will this new assignments work while destructing? this can be very handy for example ๐Ÿ˜„ :

const { a ??= "value" } = someVariable.

Current default assign while destructing only checks for undefined so nullish check can help a lot

Giving name to anonymous functions

Context: babel/babel#11362

As currently spec'd, Logical Assignment does not assign a name to anonymous functions. Consider:

let foo;
foo ??= function() {};
console.log(foo.name);

This currently should log undefined. But I think it'd be totally reasonable for this to log foo instead.

Babel hits this issue with its transform:

// Transformed Output
let foo;
foo ?? (foo = function() {});
console.log(foo.name);

That (foo = function() {}) will assign foo as the name for the anonymous function. We can work around this by using an IIFE to indirect. But I don't think the name hurts here.

Stage 3 review

  • Is there a reason that LogicalAssignmentPunctuator is its own production? I would expect to just add the new ones to OtherPunctuator. (OptionalChainingPunctuator is special in that it has a lookahead restriction, which this does not.)
  • Is there a reason the algorithm for ??= is structured differently than the algorithms for &&= and ||=? I think there's value in consistency here (so 3. If lval is neither undefined nor null, return lval. 4. Let rref [etc]).

Otherwise looks good to me.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.