You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Generics Aliasing and Partial SpecializationΒ #45419
List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback.
generics specialization
β Viability Checklist
My suggestion meets these guidelines:
This wouldn't be a breaking change in existing TypeScript/JavaScript code
This wouldn't change the runtime behavior of existing JavaScript code
This could be implemented without emitting different JS based on the types of the expressions
This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
// In external libraryexporttypeMonoid<T>={concat: (x: T,y: T)=>T;empty: T;};exporttypeMonoidFn<T>=(concat: (x: T,y: T)=>T,empty: T)=>Monoid<T>;// in user codeconstmonoid: MonoidFn<~T>=(concat,empty)=>({ concat, empty });// impossible today, T is undefined
Here we want the monoid function to still be generic and still using the original library generic definition. Using ~T tells the compiler we know that T is undefined, just make an alias.
π Partial Specialization Example
// In external libraryexporttypeAggregateFn<T,U>=(map: (item: T)=>U)=>(array: T[])=>U;// in user codeconstsum: AggregateFn<~T,number>=mapReduceSum<T,number>();// impossible today, T is undefined
Here we want to specialize AggregateFn and make sum an AggregateFn<T, number>, that is still generic but specialized for numbers. Using ~T tells the compiler we know that T is undefined, so make a partial specialization.
π» Use Cases
This is almost madatory for decent functional programming without having to redeclare functions of an external library.
Examples should be sufficient to explain a basic use case
The examples here seem to conflate generic type aliases with generic functions. It's already possible to write these types today:
exporttypeMonoid<T>={concat: (x: T,y: T)=>T;empty: T;};exporttypeMonoidFn=<T>(concat: (x: T,y: T)=>T,empty: T)=>Monoid<T>;// in user codeconstmonoid: MonoidFn=(concat,empty)=>({ concat, empty });
or
exporttypeAggregateFn2<U>=<T>(map: (item: T)=>U)=>(array: T[])=>U;// in user codeconstsum: AggregateFn2<number>=mapReduceSum<T,number>();
It seems like the thing you're looking for is a way to go from a generic type alias and a generic function or vice versa. The examples given are not enough to describe the desired semantics of such an operation, though. For example, what should happen if I write this?
declareconstm: Monoid<~T>;constx=m.empty;// What type does x have? What can be done with it?
In your first example, i don't have the option to change the external library declaration. They declared a generic type, i just want to alias it.
And in AggregateFn2 you just redeclared the external library. Meaning duplicate code, meaning loosing track of original declaration and causing error in code evolution. I can't use these kind of workarounds.
To follow your comment what i'm asking is not to just to conflate generic functions and generic aliases. It's much more genral than that. i'm asking for generics aliases like C++ have. Maybe i don't have the same vocabulary as you do, coming from a C++ background (see here. Sorry about any miss interpretations.
declareconstm: Monoid<~T>;// this is wrong, `~` should only be allowed for aliasing generics. You can't declare a Monoid<~T>.constx=m.empty;// this is invalid.
I think I am looking for something similar - generic specialization;
I would like to have something of the sort:
function encoder<T>(obj : T) : void {/* impl1 */}
function encoder<number>(obj : number) : void { /* impl2 */ }
There is a lookup that needs to be done when we call encoder in order to find which method should be called; once this method is found it can be replaced with an uniquely identified method. It would be a code generation tool in the end.
Without this we either have to resort to type checking, which is inefficient(execution time) because of conditional branches, either we have to write one method for each type that we want to call encoder with, which again is inefficient(coding time).
Activity
RyanCavanaugh commentedon Aug 12, 2021
The examples here seem to conflate generic type aliases with generic functions. It's already possible to write these types today:
or
It seems like the thing you're looking for is a way to go from a generic type alias and a generic function or vice versa. The examples given are not enough to describe the desired semantics of such an operation, though. For example, what should happen if I write this?
ecyrbe commentedon Aug 14, 2021
Hello Ryan,
In your first example, i don't have the option to change the external library declaration. They declared a generic type, i just want to alias it.
And in AggregateFn2 you just redeclared the external library. Meaning duplicate code, meaning loosing track of original declaration and causing error in code evolution. I can't use these kind of workarounds.
To follow your comment what i'm asking is not to just to conflate generic functions and generic aliases. It's much more genral than that. i'm asking for generics aliases like C++ have. Maybe i don't have the same vocabulary as you do, coming from a C++ background (see here. Sorry about any miss interpretations.
So to clarify things, when i wrote :
I meaned something like this (equivalent of c++ exemple i gave) :
And when i wrote :
I meaned this :
To answer your second question, in :
ecyrbe commentedon Dec 29, 2021
Ryan Cavanaugh (@RyanCavanaugh) do you steel need more info?
MciprianM commentedon Jul 5, 2023
I think I am looking for something similar - generic specialization;
I would like to have something of the sort:
There is a lookup that needs to be done when we call encoder in order to find which method should be called; once this method is found it can be replaced with an uniquely identified method. It would be a code generation tool in the end.
Without this we either have to resort to type checking, which is inefficient(execution time) because of conditional branches, either we have to write one method for each type that we want to call encoder with, which again is inefficient(coding time).