class-set-return

class setter's behavior is ambiguous
The value assigned to setter is returned as it is,
Let me take a very inconvenient example. (the sample from [refactoring 2th - 7.3])

class Order{
    constructor(data = {priority: "normal"}){
        this._priority = new Priority(data.priority);
    }
    set priority(aString){this._priority = new Priority(aString);} 
}
class Priority{
    constructor(value){
        if(value instanceof Priority) return value;
        if(Priority.legalValues().includes(value)) this._value = value;
        else console.error(`<${value}> is invalid for Priority`);
    }
    toString() {return this._value;}
    get _index() {return Priority.legalValues().findIndex(s => s === this._value);}
    static legalValues() {return ['low', 'normal', 'high', 'rush'];}

    equals(other) {return this._index === other._index;}
    higherThan(other) {return this._index > other._index;}
    lowerThan(other) {return this._index < other._index;}
}

The problem arises with the Client

(new Order().priority = 'normal').priority.higherThan(new Priority("low"));

this code's result is 'undefined' because new Order().priority = 'normal' return 'nomal'

But.

let orderSet = new Order();
orderSet.priority = "high";

orderSet.priority.higherThan(new Priority("low"));

it's work.

Do you guys agree how uncomfortable and unnatural this is?

AND,

I put the return code in Order Class

class Order{
    constructor(data = {priority: "normal"}){
        this._priority = new Priority(data.priority);
    }
    set priority(aString){this._priority = new Priority(aString); return this;} 
}

highlight again

set priority(aString){this._priority = new Priority(aString); return this;} 

In this statement, return is ignored.

I think this behavior is the same as inducing the writing of bad code like the one below.

class Order{
    constructor(data = {priority: "normal"}){
        this._priority = new Priority(data.priority);
    }
     setPriority(aString){this._priority = new Priority(aString); return this;}
}

Client

(new Order().setPriority('normal')).priority.higherThan(new Priority("low"));

This works the way i want

You must make it possible to remove or overwrite the return statement of the set. I think it's better to have no return statement

Proposal: https://github.com/tc39/proposal-class-set-return

Why is your desired chaining code cleaner to read and understand than the multiple-statement code?

Why is the .setPriority code worse than the setter code, when it already works how you want?

1 Like

'set'
I think the property approach is a good expression.
But what is the reason for using a 'set'
I don't know if there is any meaning as a special method used by attaching 'set'
In this way, you can just use the property access method.

I hope there will be no more 'this and that' stacks of js

Hello!

No, I don't agree. I think the unnatural part here is chaining off an assignment in a grouping parenthesis ((x = y).…). The fluent syntax with the method is much better (although I don't understand what the Order in the example is good for at all, one could just write new Priority('normal').higherThan(new Priority('low'))?).

What I think is much more important though is to not break the invariant that in x = y = z the result value of z is assigned to both x and y, no matter what x and y are or whether their setters return anything.

Thank U!
I fully agree

'set'
I expanded my opinion a little more,
Since setter is a property approach, it sounds like a better idea to behave like a function caller.

new Order().priority('normal')).priority.higherThan(new Priority("low")

The core of my suggestion is why JS setters are assigned like properties, actions are like methods, and return is like properties?

I am very curious about the reason for this design.
At the time of introduction of class,
I am sorry for the convenience of simple usability or the use of some expressions like JS.

I had a hard time understanding what this proposal is suggesting.
Firstly, setters are not unique to classes.
Secondly, the snippet of code you claim returns undefined actually throws an error.
Thirdly, I was constantly distracted by the sheer inefficiency of having a function legalValues that constructs two new arrays every time you would like to compare a priority to another.

For a bit more constructive criticism, I actually like the idea of setters being able to return a value, but I unfortunately see no applicable value to this. I don't use setters to transform values, as this produces unintuitive code (i.e I'm assigning a string to this field, so I expect that field to be a string, but it's actually a trap that returns a Priority object). The primary use for getters/setters is for computed / externally-stored values (e.g your get _index is a computed value)

1 Like