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

Overloading Operators Syntax #19859

Closed
Mike96Angelo opened this issue Nov 9, 2017 · 3 comments
Closed

Overloading Operators Syntax #19859

Mike96Angelo opened this issue Nov 9, 2017 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@Mike96Angelo
Copy link

Mike96Angelo commented Nov 9, 2017

Arithmetic Operators

add <lhs>  +,+=  <rhs>
sub <lhs>  -,-=  <rhs>
mul <lhs>  *,*=  <rhs>
div <lhs>  /,/=  <rhs>
mod <lhs>  %,%=  <rhs>
pow <lhs> **,**= <rhs>

user implements
operator add|sub|mul|div|mod|pow<T>(lhs: T, rhs: T): T

syntax:

class MyNumber {
  operator add(lhs: MyNumber, rhs: MyNumber): MyNumber {
    // code
  }
}

let a = new MyNumber(5)
let b = new MyNumber(6)

MyNumber.add(a, b)     // MyNumber(11)
// or
a + b                  // MyNumber(11)

a = MyNumber.add(a, b) // MyNumber(11)
// or
a += b                 // MyNumber(11)

a + 8                  // error Cannot convert number to MyNumber (not overloaded)

8 + a                  // '8[Object object]' (not overloaded)

emits:

class MyNumber {}
MyNumber.add = function(lhs, rhs) {
  // code
}

let a = new MyNumber(5)
let b = new MyNumber(6)

MyNumber.add(a, b)     // MyNumber(11)
// or
MyNumber.add(a, b)     // MyNumber(11)

a = MyNumber.add(a, b) // MyNumber(11)
// or
a = MyNumber.add(a, b) // MyNumber(11)

a + 8                  // '[Object object]8'

8 + a                  // '8[Object object]'

Comparison Operators

lt   <lhs>  <  <rhs>
lte  <lhs>  <= <rhs>
gt   <lhs>  >  <rhs>
gte  <lhs>  >= <rhs>
eq   <lhs>  == <rhs>
neq  <lhs>  != <rhs>
seq  <lhs> === <rhs>
sneq <lhs> !== <rhs>

global enum Comparison {
  lt = -1
  eq =  0
  gt =  1
}

user implements
operator compare<T>(lhs: T, rhs: T): Comparison

syntax:

class MyNumber {
  operator compare(lhs: MyNumber, rhs: MyNumber): Comparison {
    // code
  }
}

let a = new MyNumber(5)
let b = new MyNumber(6)

MyNumber.lt(a, b) // true
// or
a < b             // true

a < 8             // error Cannot convert number to MyNumber  (not overloaded)

9 < a             // false (not overloaded)

emits:

class MyNumber {
}

MyNumber.compare = function(lhs, rhs) {
  // code
}
MyNumber.lt = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.lt
}
MyNumber.lte = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.lt || r === Comparison.eq
}
MyNumber.gt = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.gt
}
MyNumber.gte = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.gt || r === Comparison.eq
}
MyNumber.eq = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.eq
}
MyNumber.neq = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r !== Comparison.eq
}
MyNumber.seq = function(lhs, rhs) {
  let r = MyNumber.compare(lhs, rhs)
  return r === Comparison.eq && lhs.constructor === rhs.constructor
}
MyNumber.sneq = function(lhs, rhs) {
  return !MyNumber.seq(lhs, rhs)
}

let a = new MyNumber(5)
let b = new MyNumber(6)

MyNumber.lt(a, b) // true
// or
MyNumber.lt(a, b) // true

a < 8             // false

9 < a             // false
@RyanCavanaugh
Copy link
Member

Duplicate #5407 and others; please search before logging new suggestions

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Nov 9, 2017
@Mike96Angelo
Copy link
Author

I did search and saw those others, and wasn't sure where to add this suggestion, the described implementation is different in a few ways. Using static member functions guarantees the the function will exist at runtime, (potentially using an instanceof check; if false returns the result of the normal operator). Another, not allowing a user to override individual comparison operators but instead implementing just one function that returns -1, 0, 1 (lt, eq, gt). This guarantees that all comparison operators work as expected.

My intention in sharing this implementation of a feature that has already been proposed few times is to open up more ideas as to how this feature might be implemented without having negative effects on JavaScript emit and runtime.

emit (with instanceof check):

class MyNumber {}
MyNumber.add(lhs, rhs) {
  if (lhs instanceof MyNumber && rhs instanceof MyNumber) {
    // code
  } else {
    return lhs + rhs
  }
}

This way durning runtime even if non MyNumber's are being added the default JavaScript behaviour will take place.

A more general from of an operator could be:

class `class-name` {
  operator `operator-name`(lhs: `class-name`, rhs: `any-class`): `class-name` {
    // code
  }
}

example:

class MyNumber {
  operator add(lhs: MyNumber, rhs: MyNumber): MyNumber {
    // code 1
  }

  operator add(lhs: MyNumber, rhs: Number): MyNumber {
    // code 2
  }
}

emits:

class MyNumber {}
MyNumber.add(lhs, rhs) {
  if (lhs instanceof MyNumber && rhs instanceof MyNumber) {
    // code 1
  } else if (lhs instanceof MyNumber && rhs instanceof Number) {
    // code 2
  } else {
    return lhs + rhs
  }
}

@kpdonn
Copy link
Contributor

kpdonn commented Nov 9, 2017

If you read #5407 you should have seen that the first comment on it explained that this is something Typescript is not going to do because it requires type-driven emit.

Based on your example:

class MyNumber {}
MyNumber.add = function(lhs, rhs) {
  // code
}

let a = new MyNumber(5)
let b = new MyNumber(6)
let c = 7
a + b // would emit MyNumber.add(a, b)
a + c // would emit a + c

a + b emitting MyNumber.add(a, b) because Typescript knows a and b are both MyNumber is the definition of type-driven emit so what was said about #5407 applies equally to your suggestion.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants