Skip to content

Readonly methods and readonly types #61690

Closed as not planned
Closed as not planned
@Perfectoff

Description

@Perfectoff

πŸ” Search Terms

readonly methods

βœ… Viability Checklist

⭐ Suggestion

I suggest using the readonly keyword for methods, indicating that they don't change the contents of the "this" object, but only receive data. Similar to const methods in C++. This will provide good security from possible errors, as well as better understanding of the code:

class A {
  private value = 10;

  getValue() readonly { // mark the method as readonly, prohibiting changing the contents of the object 
    this.value = 0;   // Error: can't modify readonly object
    this.setValue(0); // Error: can't call a mutating method on a readonly object
    return this.value;
  }
  setValue(val : number) {
    this.value = val;  // OK
  }
}

And the types themselves can also be marked as readonly, meaning that all their contents become readonly, and only readonly methods are available:

function foo(a : readonly A) {
  a.setValue(0); // Error: can't call a mutating method on a readonly object
  a.getValue();  // OK
} 

We already have such syntax for declaring readonly arrays. And it will become a universal declaration for any readonly objects.

And if the method does not change the contents of the class, but returns a reference to some internal object of the class, then we can overload the signature of this method in two versions (with and without readonly):

  getData() readonly : readonly number[];
  getData()          : number[];

It is also necessary to clarify that the readonly type means deep readonly of the entire nested structure of the object, not just the first-level properties. And if we need a different behavior for individual properties, we can overload the getters for them, just like in the example above.

As an additional option, we can use readonly for the declared interface or class as a whole, eliminating the need to write it for each method:

interface ReadonlySome readonly { // mark the interface as readonly
  getValue() : number;  // becomes a readonly method
  calculate(data: readonly number[]) : number;  // becomes a readonly method
}

πŸ“ƒ Motivating Example

πŸ’» Use Cases

As I mentioned above, this concept is implemented in C++, but using the const keyword:

class A {
  int _value = 10;

  int getValue() const { 
    _value = 0;   // Error
    setValue(0); // Error
    return _value;
  }
  void setValue(int val) {
    _value = val; // OK
  }
  foo(const A& a) {
    a.setValue(0); // Error
  }
};

It is also partially implemented in C#, but in a very limited version. I don't see any reason why it couldn't be fully implemented.

In TypeScript as an alternative we can try to wrap "this" in some kind of typing:

class A {
  readonlyMethod(this : SomeReadonlyWrap<A>) { }
}

but I haven't found the right implementation of this wrapper yet. And anyway, it's very cumbersome to write it like that for all methods, especially in template classes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions