Home > Software design >  How to make a static class value a method call like a getter property
How to make a static class value a method call like a getter property

Time:04-04

I have this class:

export class Vec2 {
  static unit = new Vec2(1, 1)

  get clone(): Vec2 {
    return new Vec2(this.x, this.y)
  }

  constructor(readonly x: number, readonly y: number) {}


  scale(k: number) {
    this.x *= k
    this.y *= k
  }
}

I want to use it like this:

let ten_v = Vec2.unit.scale(10)
let twenty_v = Vec2.unit.scale(20)

As you can see I start from a unit vector and scale it to get the vector I want.

This is the API I want no Vec2.unit() or Vec2.unit.clone.scale(10).

The problem with this is, scale method modifies the unit vector which is a static object, and I don't want that.

So I would like a static getter property just like object instances have getter properties that expands into method calls. Like clone in this example but static.

CodePudding user response:

If you're targeting ECMAScript 2015 or higher (which you, let's be honest, probably should be in 2022), you can actually just declare getters with the static modifier.

static get UNIT() {
  return new Vec2(1, 1);
}

But read on, because I want to challenge the frame of this question a bit. The frame challenge is this: Why is your vector mutable at all? Vectors are nice mathematical objects, so why not have all of those functions just return new ones?

export class Vec2 {
  static UNIT = new Vec2(1, 1);

  readonly x: number;
  readonly y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  scale(k: number) {
    return new Vector(this.x * k, this.y * k);
  }

}

Now you don't have to worry about whether or not existing vectors get modified, because vectors never get modified. You don't need clone anymore, since there's never a use case to intentionally have two identical-looking vectors. And the static field is fine since, again, everything you can possibly do to it is immutable.

I've been working with the Minecraft Bukkit API, and it has a mutable Vector class. So I can speak from personal experience when I say that it is a royal pain to work with. Every time you want to modify a vector, you defensively .clone because you're not sure if the function you called just did that or not, and anytime you want to modify an existing vector, you end up assigning it back because, again, you're not sure if they gave you the real vector or a clone. Sometimes it's documented, but sometimes it's not. So really, save yourself and everyone who uses your library the immense headache and just make it immutable.

  • Related