Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why no overloaded constructor implementations? #10696

Closed
sclausen opened this issue Sep 3, 2016 · 2 comments
Closed

Why no overloaded constructor implementations? #10696

sclausen opened this issue Sep 3, 2016 · 2 comments

Comments

@sclausen
Copy link

sclausen commented Sep 3, 2016

Its not really a Design proposal, it's more a question why TypeScript doesn't have it.
In Java it's common to write more than one version of a function to support many different argument constellations. For example a vector could be constucted with a start and endpoint or just the start point or just the coordinates of those points and so on.
Here is an example:

export class Vector {
  public p1;
  public p2;
  public p3;
  public q1;
  public q2;
  public q3;

  constructor(x1: number, x2: number, x3: number);
  constructor(P: Point);
  constructor(Ps: Point, q1: number, q2: number, q3: number);
  constructor(p1: number, p2: number, p3: number, Pe: Point);
  constructor(Ps: Point, Pe: Point);
  constructor(p1: number, p2: number, p3: number, V: Vector);
  constructor(Ps: Point, V: Vector);
  constructor(Vs: Vector, V: Vector);
  constructor(p1: number, p2: number, p3: number, q1: number, q2: number, q3: number);
  constructor(p1: any, p2?: any, p3?: any, p4?: any, p5?: any, p6?: any) {
    if (this.validateParameters(["number", "number", "number"], [p1, p2, p3, p4, p5, p6])) {
      this.constructor1(p1, p2, p3);
    } else if (this.validateParameters([Point], [p1, p2, p3, p4, p5, p6])) {
      this.constructor2(p1);
    } else if (this.validateParameters([Point, "number", "number", "number"], [p1, p2, p3, p4, p5, p6])) {
      this.constructor3(p1, p2, p3, p4);
    } else if (this.validateParameters(["number", "number", "number", Point], [p1, p2, p3, p4, p5, p6])) {
      this.constructor4(p1, p2, p3, p4);
    } else if (this.validateParameters([Point, Point], [p1, p2, p3, p4, p5, p6])) {
      this.constructor5(p1, p2);
    } else if (this.validateParameters(["number", "number", "number", Vector], [p1, p2, p3, p4, p5, p6])) {
      this.constructor6(p1, p2, p3, p4);
    } else if (this.validateParameters([Point, Vector], [p1, p2, p3, p4, p5, p6])) {
      this.constructor7(p1, p2);
    } else if (this.validateParameters([Vector, Vector], [p1, p2, p3, p4, p5, p6])) {
      this.constructor8(p1, p2);
    } else if (this.validateParameters(["number", "number", "number", "number", "number", "number"], [p1, p2, p3, p4, p5, p6])) {
      this.constructor9(p1, p2, p3, p4, p5, p6);
    }
  }

  private constructor1(x1: number, x2: number, x3: number) {
    this.p1 = 0;
    this.p2 = 0;
    this.p3 = 0;
    this.q1 = x1;
    this.q2 = x2;
    this.q3 = x3;
  }

  private constructor2(P: Point) {
    this.p1 = 0;
    this.p2 = 0;
    this.p3 = 0;
    this.q1 = P.x1;
    this.q2 = P.x2;
    this.q3 = P.x3;
  }

  private constructor3(Ps: Point, q1: number, q2: number, q3: number) {
    this.p1 = Ps.x1;
    this.p2 = Ps.x2;
    this.p3 = Ps.x3;
    this.q1 = q1;
    this.q2 = q2;
    this.q3 = q3;
  }

  private constructor4(p1: number, p2: number, p3: number, Pe: Point) {
    this.p1 = p1;
    this.p2 = p2;
    this.p3 = p3;
    this.q1 = Pe.x1;
    this.q2 = Pe.x2;
    this.q3 = Pe.x3;
  }

  private constructor5(Ps: Point, Pe: Point) {
    this.p1 = Ps.x1;
    this.p2 = Ps.x2;
    this.p3 = Ps.x3;
    this.q1 = Pe.x1;
    this.q2 = Pe.x2;
    this.q3 = Pe.x3;
  }

  private constructor6(p1: number, p2: number, p3: number, V: Vector) {
    this.p1 = p1;
    this.p2 = p2;
    this.p3 = p3;
    this.q1 = p1 + V.q1;
    this.q2 = p2 + V.q2;
    this.q3 = p3 + V.q3;
  }

  private constructor7(Ps: Point, V: Vector) {
    this.p1 = Ps.x1;
    this.p2 = Ps.x2;
    this.p3 = Ps.x3;
    this.q1 = Ps.x1 + V.q1;
    this.q2 = Ps.x2 + V.q2;
    this.q3 = Ps.x3 + V.q3;
  }

  private constructor8(Vs: Vector, V: Vector) {
    this.p1 = Vs.q1;
    this.p2 = Vs.q2;
    this.p3 = Vs.q3;
    this.q1 = Vs.q1 + V.q1;
    this.q2 = Vs.q2 + V.q2;
    this.q3 = Vs.q3 + V.q3;
  }

  private constructor9(p1: number, p2: number, p3: number, q1: number, q2: number, q3: number) {
    this.p1 = p1;
    this.p2 = p2;
    this.p3 = p3;
    this.q1 = q1;
    this.q2 = q2;
    this.q3 = q3;
  }

  private validateParameters(pattern: any[], args: any[]) {
    return args.every((arg, index) => {
      if (arg === pattern[index]) {
        return true;
      } else if (typeof arg === pattern[index]) {
        return true;
      } else if (typeof pattern[index] === "function" && arg !== undefined && arg instanceof pattern[index]) {
        return true;
      } else {
        return false;
      }
    });
  }
}

So if you want to write the constructor implementation you have to make a single constructor and check which parameters have been provided and this can get very confusing if you don't just have two or three parameters, but more like in this example. Writing implementations for each constructor would be way more readable, so why doesn't typescript support this, since it's a not very far fetched feature?

@DanielRosenwasser
Copy link
Member

It's not clear the extent to which people will accept runtime introspection to dispatch overloads. People often have differing opinions on what sort of check is appropriate in different places. Is it complete structural compatibility? Should instanceof be used?

See #3442 for an issue which proposed this. The TL;DR is given by @mhegazy in that we don't do any sort of type-driven code generation. Ideally this could be a custom transformation in the future.

@sclausen
Copy link
Author

sclausen commented Sep 4, 2016

Thanks @DanielRosenwasser. If I get the mentioned issue right, it totally would be possible, but would break typescript's design goals so it won't be implemented.
I'm sad, since I share the opinion of @jhchen or @AlicanC @ToastHawaii.

@sclausen sclausen closed this as completed Sep 4, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants