GithubHelp home page GithubHelp logo

sebmarkbage / ecmascript-undefined-propagation Goto Github PK

View Code? Open in Web Editor NEW
76.0 8.0 4.0 2 KB

ECMAScript proposal to relax the rules to return `undefined` for property access on `null` or `undefined` instead of throwing.

ecmascript-undefined-propagation's Introduction

Silent Property Access on null/undefined for ECMAScript

TL;DR: Relax the rules to return undefined for property access on null or undefined instead of throwing.

This is going to be a very controversial proposal but if it works it would be a very elegant solution to a significant problem.

The Problem

How do you access deep properties into an object where intermediates may be null or undefined?

Currently the syntax is too bloated:

let abc = a == null || a.b == null || a.b.c == null ? null : a.b.c;

With longer property names this becomes very messy to the point that library helpers keep being reinvented to minimize the boilerplate.

It is also a very common operation in JavaScript applications because they're often just JSON to UI processors.

Examples

The proposed semantics is that property access on null or undefined returns undefined. Any other ToObject operation still throws.

let a = null;
let abc = a.b.c; // undefined
let a = undefined;
let abc = a.b.c; // undefined
let a = { b: null };
let abc = a.b.c; // undefined
let a = { b: { c: null } };
let abc = a.b.c; // null
let a = { b: null };
delete a.b.c; // throws a TypeError

Specification

The specification changes simply changes the runtime semantics for property access and returns undefined in the case the baseValue is null or undefined.

MemberExpression : MemberExpression [ Expression ]

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let propertyNameReference be the result of evaluating Expression.
  4. Let propertyNameValue be ? GetValue(propertyNameReference).
  5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
  6. If the code matched by the syntactic production that is being evaluated is strict mode code, let strict be true, else let strict be false.
  7. If baseValue is null or undefined, return a value of type Reference whose base value component is undefined, whose referenced name component is propertyKey, and whose strict reference flag is strict.
  8. Return a value of type Reference whose base value component is baseValue, whose referenced name component is propertyKey, and whose strict reference flag is strict.

MemberExpression : MemberExpression . IdentifierName

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let propertyNameString be StringValue of IdentifierName.
  4. If the code matched by the syntactic production that is being evaluated is strict mode code, let strict be true, else let strict be false.
  5. If baseValue is null or undefined, return a value of type Reference whose base value component is undefined, whose referenced name component is propertyNameString, and whose strict reference flag is strict.
  6. Return a value of type Reference whose base value component is baseValue, whose referenced name component is propertyNameString, and whose strict reference flag is strict.

Known Issues

Early errors are nice

The general objection to this is that it won't catch errors early enough. This is an area where I feel like the ship has already sailed for JavaScript. Generally the language is very permissive. Even without this undefined values travel around code through calls like a.b and turn into NaN freely. Generally this is solved with additional tooling on top of the runtime semantics such as linters.

If you truly want to protect against this then adding strong typing through dynamic runtime checks or static typing through static type systems like TypeScript or Flow is going to cover a lot more than just this one special case.

Why the special case?

These are the only types that currently DOES throw so this is actually getting rid of a special case. boolean, number, string and symbol all doesn't throw. It's no weirder that 123.foo() not throwing.

Object.assign and many others already special case null and undefined to be treated roughly like an empty object anyway because it is so convenient.

Is this change web safe and secure?

I don't know. It is plausible that things on the web relies on an error being thrown. Either accidentally or intentionally as a security measure. It would have to be tested and evaluated.

Usually relaxing errors is something we let ourselves do but this might be frequent enough that it might cause problems.

No explicit syntax for communicating intent

Unlike other proposals this would come with a way to explicitly communicating the intent to access property on an object that might be null.

For example, type systems generally want to warn you if you access a missing property. It can't do that if this is a legit use case.

This is already a problem for the a.b case where b may or may not exist on a if a is a union type.

JavaScript doesn't generally add syntax for the purpose of supporting type systems neither. It's up to the type systems to propose additional syntax for communicating this intent if you use them.

Why not existential or null propagator operator?

There have been long lived proposals to support an explicit operator to do this:

let abc = a?.b?.c;

CoffeeScript, C#, and others have this.

I don't really have any concrete reason why this wouldn't be a good idea, but I'd like to explore an alternative and see if that is possible.

ecmascript-undefined-propagation's People

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

oldergod

ecmascript-undefined-propagation's Issues

Destructuring

Would this also work with destructuring?

const { foo } = null
// current: TypeError: Cannot match against 'undefined' or 'null'.
// with this?: `foo === undefined`

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.