• Home
  • Categories
  • Recent
  • Popular
  • Top
  • Tags
  • Users
  • Groups
  • Documentation
    • Home
    • Read API
    • Write API
    • Plugin Development
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
v3.5.2 Latest
Buy Hosting

Proposal for constant Class and Object members and immutable Classes and Objects shorthand

Scheduled Pinned Locked Moved General Discussion
1 Posts 1 Posters 1.0k Views
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • PitaJP Offline
    PitaJP Offline
    PitaJ Global Moderator Plugin & Theme Dev
    wrote on last edited by PitaJ
    #1

    I propose to either add a new ability for
    the const keyword or use the reserved word final to make
    non-writable object and class members.

    Note: The TypeErrors are thrown following the behavior of Object.freeze or
    a { configurable: false, writable: false } property descriptor. They
    will be thrown in a "use strict"; environment, but usually not
    otherwise.

    Constant Class or Object members / properties / fields / methods

    Use final, since it is an unused reserved word, or possibly const to define constant Class or Object members:

    class X {
      // const / final now makes static class properties
      // non-writable, and non-configurable
      static const abc = 123; 
      static final abc = 123;
    
      // also works to make constant private properties
      const #def = 456;
      final #def = 456;
    
      // as well as constant normal class fields, if you're into that
      const ghi = 789;
      final ghi = 789;
    
      // and constant private / static / normal methods
      static const doSomething() { }
      static final doSomething() { }
    
      const #somethingPrivate() { }
      final #somethingPrivate() { }
    
      const cantChangeMe() { }
      final cantChangeMe() { }
    
      constructor(a = 3) {
        const somethingPrivate = this.#somethingPrivate;
        // throws new TypeError('Assignment to constant property.')
        this.#somethingPrivate = function () { return a; }
        this.#somethingPrivate === somethingPrivate // true
    
        const def = this.#def;
        // throws new TypeError('Assignment to constant property.')
        this.#def = 1000;
        this.#def === def // true
      }
    }
    
    const x = new X();
    
    const ghi = x.ghi;
    // throws new TypeError('Assignment to constant property.')
    x.ghi = 2000;
    x.ghi === ghi // true
    
    const doSomething = X.doSomething;
    // throws new TypeError('Assignment to constant property.')
    X.doSomething = function doSomethingElse() { };
    X.doSomething === doSomething // true
    
    const cantChangeMe = X.prototype.cantChangeMe;
    // throws new TypeError('Assignment to constant property.')
    X.prototype.cantChangeMe = function yesICan() { }; 
    X.prototype.cantChangeMe === cantChangeMe // true
    
    
    const o = {
      // const / final can be used in normal object literals, too
      const things() { },
      final things() { },
    
      const prop: 5,
      final prop: 5,
    };
    
    const things = o.things;
    // throws new TypeError('Assignment to constant property.')
    o.things = function stuff() { };
    o.things === things // true
    
    const prop = o.prop;
    // throws new TypeError('Assignment to constant property.')
    o.prop = 11;
    o.prop === prop // true
    

    This could be transpiled by simply using Object.defineProperty like so,
    at least on public members:

    class X {
      static abc = 123;
      static doSomething() { }
      cantChangeMe() { }
    
      constructor() { }
    }
    
    ['abc', 'doSomething', 'cantChangeMe'].forEach(key =>
      Object.defineProperty(X, key, { configurable: false, writable: false })
    );
    
    
    const o = {
      things() { },
      prop: 5,
    };
    
    ['things', 'prop'].forEach(key =>
      Object.defineProperty(o, key, { configurable: false, writable: false })
    );
    

    Shorthand for Immutable Classes and Objects

    Defining everything as final or const in a Class or Object doesn't quiet
    do the job. What if we want true immutability?

    I've also looked into some kind of special syntax for creating immutable
    objects and making classes return immutable objects. Maybe we could use
    final for that, as well?

    // The static members and prototype of this class are shallow immutable.
    // Any object it returns is also shallow immutable,
    // similar to `return Object.freeze(this)` as the last line in the constructor,
    // though since it uses a keyword, it could throw an error on an attempt to override
    final class ConstantObject {
      static abc = 123;
      static doSomething() { }
      cantChangeMe() { }
    
      constructor() {
        this.d = 8;
      }
    }
    
    const constantObject = new ConstantObject();
    
    const c = constantObject.c;
    // throws new TypeError('Assignment to constant property.')
    constantObject.c = 321;
    constantObject.c = c // true
    
    const doSomething = ConstantObject.doSomething;
    // throws new TypeError('Assignment to constant property.')
    ConstantObject.doSomething = function doSomethingElse() { };
    ConstantObject.doSomething === doSomething // true
    
    const cantChangeMe = ConstantObject.prototype.cantChangeMe;
    // throws new TypeError('Assignment to constant property.')
    ConstantObject.prototype.cantChangeMe = function yesICan() { }; 
    ConstantObject.prototype.cantChangeMe === cantChangeMe // true
    
    
    // No members can be added / modified / deleted from this shallow immutable object.
    const finalObject = final {
      prop: 5,
      things() { },
    };
    
    const things = finalObject.things;
    // throws new TypeError('Assignment to constant property.')
    finalObject.things = function stuff() { };
    finalObject.things === things // true
    
    const prop = finalObject.prop;
    // throws new TypeError('Assignment to constant property.')
    finalObject.prop = 11;
    finalObject.prop === prop // true
    

    This could be transpiled essentially by just using Object.freeze and Object.defineProperty:

    const ConstantObject = (() => {
      class ConstantObject {
        static abc = 123;
        static doSomething() { }
        cantChangeMe() { }
    
        constructor() {
          this.d = 8;
          return Object.freeze(this);
        }
      }
    
      Object.defineProperty(ConstantObject, 'prototype', { 
        value: Object.freeze(ConstantObject.prototype),
      });
      return Object.freeze(ConstantObject);
    })();
    
    
    const finalObject = Object.freeze({
      prop: 5,
      things() { },
    });
    


    What do you think? I'm currently leaning towards using the final keyword for everything.
    Both sides have pros and cons.

    const final
    Pros • Meaningful word • Unused
    • Fits existing syntax; AKA const x = 5 -> const x: 5 • Meaning could be closer if devs want to initialize after definition
    • Familiar to Java devs
    Cons • Could be overloaded in usage • Less meaningful to C / JS devs, could be confusing
    1 Reply Last reply
    0

Copyright © 2023 NodeBB | Contributors
  • Login

  • Don't have an account? Register

  • Login or register to search.
Powered by NodeBB Contributors
  • First post
    Last post
0
  • Home
  • Categories
  • Recent
  • Popular
  • Top
  • Tags
  • Users
  • Groups
  • Documentation
    • Home
    • Read API
    • Write API
    • Plugin Development