Since it's very unlikely that the extension methods will ever be implemented in a call-site-rewrite manner, please consider adding infix operators to enable writing in functional style similarly to what can be done in Haskell:
Monoids
function '+'<a>(left: a[], right: a[]) : a[] {
return left.concat(right);
}
[1, 2, 3] '+' [4, 5]; // [1, 2, 3, 4, 5]
Monads
function '>>='<a, b>(promise: Promise<a>, bind: (value: a) => Promise<b>) : Promise<b> {
return promise.then(bind);
}
$.get('/get') '>>=' x => $.post('/save', x + 1)
Functors
function '.'<a, b, c>(inner: (value: a) => b, outer: (value: b) => c) : (value: a) => c {
return function(value: a) : c {
return outer(inner(value))
}
}
function f(x: X) : Y { }
function g(y: Y) : Z { }
(f '.' g)(x); // z
I love this functional stuff but I will be honest and say this isn't likely to happen unless JS ends up adding support for it (in which case I could imagine some popular libraries leveraging this).
What would you expect the emit to be for functions that are named like this but which aren't valid function names in JS?
Worth mentioning: ES Future might have operator overloading
Since all threads about operators oveloading were closed as duplicate of this thread, I suppose this is the right place to speak of it.
I understand, the close javascript <-> typescript code argument, so I understand that it would be awful to have in javascript "strange names" that translate typescript overloaded operators.
However:
I am implementing a C# style IQueryable<T>
,and having operator overloading would make posssible to have exactly the same C# syntax. Thanks to methods and operator overloading then I might organize in such a way that function of the type m => m.Name == "Peter" || m.Surname == "Peter"
passed to where clauses once executed on a special object(instead of T) would produce the syntactic tree of the expression(which is what I need) instead of the "usual" result. Without operator overloading I'll be forced to write awful stuffs like:
m=> m.Name.eq("Peter")
.or(m.Surname.eq("Peter"))
as mentioned by @basarat ES7 might have operator overloading
Just as a heads up @frankabbruzzese, it didn't. ES2016 was finalized with a new exponentiation operator (**
) but that's about it. I don't think we could do this without an advanced-stage proposal on ECMAScript itself.
And there is no proposal, stage 0 or otherwise regarding this. I just looked. I can't even find an inactive proposal.
I was thinking just to a syntactic sugar for existing methods. Something like:
class Person{
name: string;
Id: number;
constructor(theName: string, theId: number) { this.name = theName; this.Id=theId;}
Equal(other: Person): '==' {
Id == other.Id;
}
}
We define a standard method, like Equal
above and then provide an operator to use in place of the method, as a syntactic sugar. When code is transpiled operator disappears and is substituted by the original method. Javascript code remains human readable and close to the original typescript.
The way ECMAScript will likely solve this is through well known Symbol
s. It would be better to find a solution that embraces that... For iterators that is already a feature of the language by adding a Symbol.iterator
to an object/class. The best possible solution for your desires is to champion ECMAScript to recognise additional well known symbols and then everyone benefits.
@kitsonk not clear how symbols myght help me. The only way a well known symbols might help me is a property indexed by a symbol that returns the syntactic tree of a function...that is what I need (without being forced to load a whole JavaScript compiler written in Javascript). However, not sure actual implementations stores syntactic trees in functions, so that they might accomodate with an acceptable effort this feature.
Anyway substituting a.Equal(b)
with a == b
...and symilar might simplify a lot several JavaScript fluent interfaces
The "vision" of Symbols is that they will allow modification of run-time behaviour. For example, if ECMAScript agreed on Symbol.looseEquals
for example, you could do this:
class Person{
name: string;
Id: number;
constructor(theName: string, theId: number) { this.name = theName; this.Id=theId;}
[Symbol.looseEquals](other: Person): boolean {
this.Id == other.Id;
}
}
const personA = new Person();
const personB = new Person();
console.log(personA == personB);
It is use cases like this that Symbols were intended for. Like with the Symbol.toPrimitive
and Symbol.toStringTag
which deal with coercion of objects by the run-time engine.
TypeScript taking this on, as described though, is an anti-pattern for TypeScript. Design goal number 8:
Avoid adding expression-level syntax.
So even if there was a proposal that the TypeScript team would consider, it should align to the way these things are meant to be accomplished in ECMAScript, not introduce new constructs.
In fact there is nothing preventing you know from creating a Symbol
and using it internally and doing something similar already:
Symbol.looseEquals = Symbol('looseEquals');
class Person {
name: string;
Id: number;
constructor(theName: string, theId: number) { this.name = theName; this.Id=theId;}
[Symbol.looseEquals](other: Person): boolean {
this.Id == other.Id;
}
}
function looseEquals(a: any, b: any): boolean {
if (a[Symbol.looseEquals]) {
return a[Symbol.looseEquals](b);
}
return a == b;
}
const personA = new Person();
const personB = new Person();
console.log(looseEquals(personA, personB));
@kitsonk ,
Ok if a symbol for each operator would be inserted in a future standard I would have the problem solved. However, actually, may be I will be dead for the time an acceptable browser support would be available. We are not speaking of just looseEqual but of all comparison and boolean operators...
In the meantime TypeScript can't simulate this with transcompilation, so I remain with your final example.
However, your last looseEquals
example don't get ready of parentheses and define a function in global space. An actual implementation whould use modules/amespaces so it should be something like myNamespace.looseEquals of better myNamespace.eq.
I am writing an IQueryable library, that developers may use with not trivial filters or selections like:
context.Persons.where(m => (m.Name.startsWith(x) || m.surName == x) && date >= d)......
If I substitute each ==
, &&
and ||
with ns.eq
, ns.or
, and ns.and
...+ needed parentheses expression would become very hard to read.
Here the point is that operator syntax makes expressions easier to read and understand, that's why expressions are used just with basic types in javascript (complex types cant use operators), that's why most of libraries prefer using long fluent interfaces to the use of expressions that would imply nested parentheses almost impossible to read and undersdtand.
This is boiling down to "I want it, I want it" irrespective of the feedback that TypeScript is highly unlikely to introduce a feature for the reasons stated above. Yet you continue to say "but I want it" and feel restating it will somehow overcome the reasons stated above of why it is unlikely to be introduced. TypeScript is not a separate language, it is intended to be a superset of ECMAScript. Dart is an example of a separate language.
@kitsonk , sorry if my last post sounded like a kind of protest. It wasn't my intention. It was not with you, or with your team, but just sayng to myself: "ok stop on this path and accept Javascript limitations: let use a fluent interface instead of expressions".
In fact while I appreciate your time and your suggestions I don't think there is a solution or a kind of acceptable compromise on this subject. The only way is to renounce to the usage of complex expressions.
I understand your reasons: moving away from javascript standard might cause the "death" of TypeScript in a short time. TypeScript success as compared with other transpilation based frameworks is due just to this, That is why I am thinking just there is no solution! I could have moved toward another framework...but then my software would havel been thrown away by the next wave of JavaScript changes. So I prefer accepting JavaScript limitation and use a fluent interface.
Also looking for kinda compromise makes no sense. If most of advanced object-based languages implemeted operator overloading is because there is no other way to simplify expressions. The point here is that JavaScript is not exactly an object based framework: as a matter of fact there is no run-time support for types...just prototypes.
Also pushing toward the implementation of new well known symbols wouldn't help. Operator overloading has some overlap with "standard behavior customization", but it is quite different and its purpose is different. In fact operator overloading allows the usage of an operator also in types that natively do not support that operator.So, for instance, Symbols might provide overloaded comparison operator just for types that natively admits a comparison, all other types would be coerced to basic types in any a case instead of using a different definition of them.
I analyzed also true "operator overloading proposals", but strangely enough they were publicly introduced in talks of gusys from Google and Mozilla, but never submitted??? Very strange!
I'll try to ask them why, and if they think a similar proposal will be submitted and pushed.
Again thanks for your time.
or with your team
Just for clarity, the TypeScript team isn't "my team"... I am just a heavy user of TypeScript, maintainer of a major JavaScript framework of which the next version is TypeScript based.
Also, I am stating that _if_ ECMAScript ever supports operator overloading it will be done via Symbols, as that is the intent of Symbols in the first place. TC39 has made that path clear. From bitter experience, I know the TypeScript team will not invent new solutions for things that are likely to become standards in the future. I respect their decision to hold to their design goals, although it has complicated things. They of course hold to that due to bitter experience related to the ES Module Syntax and the "cost" of not keeping TypeScript aligned. I think it has less to do with the "death" of TypeScript as much as TypeScript is in it for the long haul, with maybe a vision that TypeScript has the potential to become ECMAScript. The only way to do that is ensure that TypeScript is always a superset of ECMAScript, something that I believe is why TypeScript has had success where as items like Dart has faded.
We, in the web, have all paid the cost of isolation and obsolescence due to not getting wide agreement before implementation. TypeScripts "domain" of authority, if you will, is around types and how those are handled. Maybe a bit around meta data and reflection. It also led the charge in decorators, but under a flag. Operator overloading is clearly not something that is core to the vision of TypeScript, no matter how useful it is, therefore, it is highly unlikely the team will suddenly decide that new expression level syntax for operator overloading would be the right thing to do, especially when the proposed constructs here wouldn't ever fit into ECMAScript.
@kitsonk,
I don't think that symbols will ever solve. >, >=, <=, and <, are defined just for basic types. Any attempt to use them with other types corces that types to basic types (string). Thus, defining a well known Symbol for them would only work for basic types. You would never use, say <, with a generic object types (though you might customizethe way it is coerced to a string). The same is true for arithetic operators that corce to basict types. ||, &&, ==, !=, ! instead might be overloaded on all types
About TypeScript, I think, they NEED to be quite "strict" on implementations. In the past they already refused pull requests implementing operator overloading.
I tried to remove some of the reasons they refuse it by restating it as a syntactic sugar on already existing methods...but I understand your point: if, as a rule, they would accept similar proposals, they would eventually move quite far from ECMA standard, thus transforming TypeScript just in one of the thousands of JavaScrip frameworks
@frankabbruzzese, which JavaScript frameworks provide static typing and operator overloading? I'm using TS now for heavy duty canvas work and the lack of operators for even vectors is a show stopper. I guess TS's goal of JavaScript purity is not my own, and if there is a more appropriate framework focused instead more on programmer productivity, I would love to use it instead.
I'm also using canvas. So while using TypeScript was an amazing experience(I'm a C# dev) the lack of operators makes the math around Rectangles, Points, Sizes impossible to read and maintain.
Would love to see them.
@mcdirmid , Google DART supports operatos overloading. However, Google choice for Angular2 favourite framework was TypeScript, not DART, since Angular2 itself was wriiten in TypeScript. So it appears that the language the more likely to survive the next few years is TypeScript. Other languages might de facto be abandoned in a a few years, Thus, notwithstanding the absence of operator overloading I decided to go on with TypeScript.
In one of the closed issues someone raised the point of rewriting operators to functions in the emitted JS (being a type-driven source emitting) going against the close correspondence that TS wants to maintain.
How about allowing operator functions only as 'aliases'. That is, the functionality has to be written in a normal function first, then an alias is created to forward to that function. The emitted JS uses the main function's name throughout.
Basically just syntax for plain assignment (assigning the main function name to the operator) that requires the assigned value to be a function of 1 or 2 arguments.
Something like:
function _myadd(x: Student, y: Student): number {
// blah
return blah;
}
function '+' = _myadd;
please just find a way to add operator overloading to it. :'(
each second without operator overloading in typescript, a baby cat is killed in uganda... :'(
It would be nice to add such a feature with the experimental status to give the TypeScript team the freedom to break-change operator overloading when ES decides to include it in the official specifications.
With Symbol
or as an alias of an existing function, whatever, but we really need it now to make our code readable and maintainable when dealing with vectors! :)
Relevant to https://github.com/Microsoft/TypeScript/issues/2319#issuecomment-260171739
https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators
Same idea in Purescript
what about using backticks in the function definition and call:
function `+`<a>(left: a[], right: a[]) : a[] {
return left.concat(right);
}
[1, 2, 3] `+` [4, 5]; // [1, 2, 3, 4, 5]
We won't be doing this unless a proposal goes through the ECMAScript process
@RyanCavanaugh how does one go about doing that?
@graingert https://tc39.github.io/process-document/
@RyanCavanaugh ok: https://esdiscuss.org/topic/suggestion-infix-operators-functions
Most helpful comment
I'm also using canvas. So while using TypeScript was an amazing experience(I'm a C# dev) the lack of operators makes the math around Rectangles, Points, Sizes impossible to read and maintain.
Would love to see them.