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

Introduce compact callback declaration #14173

Closed
unional opened this issue Feb 19, 2017 · 17 comments
Closed

Introduce compact callback declaration #14173

unional opened this issue Feb 19, 2017 · 17 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript

Comments

@unional
Copy link
Contributor

unional commented Feb 19, 2017

tsc: 2.1.6

Originally from: http://stackoverflow.com/posts/42322317

I can see that needing to declare the argument name in the callback function type could be redundant, and MAY BE make even less sense in higher order function.

So maybe it is beneficial to support this shorten form arrayCompare(f: (Ord) => (Ord) => boolean)?

Do you see other application?

One drawback it that the compiler need to add arbitrary names to make completion consistent:
image

@HerringtonDarkholme
Copy link
Contributor

The problem is we already have loosely typed function declaration like var eq: (a, b) => boolean where a/b only stands for arity but not type. 😞

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

Yes, but on the other hand we can have this rule kicks in only if the a / b can be resolved as types.

I think that is still doable.

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 20, 2017

only if the a / b can be resolved as types.

This rule is too sloppy, consider:

(str, number) => string

The first one is not a type, but the second one is. How to resolve this signature?

Also, this requires resolving new parser conflict

(Gen<A, B>) => string

Cannot be determined to be a syntax error or not.

Another confusion:

type A = ({a: string, b: number}) => string // or ([string, number]) => string
var A = ({a: string, b: number}) => string // ([string, number]) => string

has totally different meaning.

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

(str, number) => string

Would stay this won't apply. number is still parameter name. i.e.: (str: any, number: any) => string

type A = ({a: string, b: number}) => string

is a valid type, because you are doing a type declaration.

var A = ({a: string, b: number}) => string

this would be an implementation.

One thing TypeScript good at is a clear separation of type definition and implementation, because the implementation side is just JavaScript.
So determining which is which is not too difficult (unless I make mistakes, which always happen more then I would like to. 🌷 ).

Of course, there could be still confusing cases.
It would be great to list them out and see if this proposal make sense or not. 🌷

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

(Gen<A, B>) => string

Not sure what do you mean here. If this proposal is accepted and implement, would it be considered correct syntax? e.g. foo<A,B>(fn: (Gen<A,B>) => string)?

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 20, 2017

(Gen<A, B>) => string

is a syntax error now. If the proposal is accepted, this is no longer a syntax error. Error handling in parser requires rewriting (this impacts transpiling).

Another problem: we don't have types for spread arguments:

(a, ...b: any[]) => void

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

Another problem: we don't have types for spread arguments:

(string, ...string[]) => void ?

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 20, 2017

Now consider: merging all rules mentioned above into one rule to parse and check function type (Especially, pay attention to how errors should be reported. For example, how generic argument type error is reported as I pointed above). The final rule will quickly explode when new syntax is introduced. Also, as a proposal, keep an eye on breaking change.

I found myself perplexed when writing it out. It probably means users will be confused too.

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

Error handling in parser requires rewriting (this impacts transpiling).

Yes, that may need to change, but also may not. It depends on when the arbitrary argument is injected.

When (Gen<A,B>) => string is converted back to (arg1: Gen<A, B>) => string, then the error handling would be the same.

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

merging all rules mentioned above into one rule to parse and check function type

Actually there is only two:

  1. If in type declaration, the code is in the format of (Type1, Type2, ...TypeN) => TypeR (or declaration without named argument), then
  2. add the arbitrary argument so it becomes (arg1: Type1, arg2: Type2, ...argn: TypeN) => TypeR

Then parse as normal.

@HerringtonDarkholme
Copy link
Contributor

When (Gen<A,B>) => string is converted back to (arg1: Gen<A, B>) => string

When? You have to know Gen is a generic type at first because

we can have this rule kicks in only if the a / b can be resolved as types.

If it isn't, should Gen<A, B> parsed as the old style function type? So it is a syntax error, not a type error.

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

When? You have to know Gen is a generic type at first because

If Gen / A / B / string can be resolved as Type and generics, then yes, otherwise, no.

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 20, 2017

No, you cannot.

To resolve type information, you need to have AST because TSC is syntax driven. To have AST, you have to parse. To parse you have to know if Gen is resolved to type. To resolve type information, you need to ... (recursion here).

The rule you listed is not sufficient, if without specifying how type information is integrated in parsing.

@unional
Copy link
Contributor Author

unional commented Feb 20, 2017

I see. I'm mentally handicap when talking about AST, so I trust your judgement. 😛

In the SO post it mentioned Haskell.
So Haskell seems to support this syntax.

Can some idea be drawn from that? Or it is a radical change?

Would it be possible that when tsc parses (Gen<A, B>) => string, it recognizes the param name is missing and perform the injection there so it can continue parsing?

One key is this rule only applies during type declaration, i.e. type A = ..., fn: ..., interface X { (...) => ..., etc.

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 20, 2017

So Haskell seems to support this syntax.

Of course. And Haskell does not support untyped function type (a, b) => void so no conflict.

Would it be possible that when tsc parses (Gen<A, B>) => string,

I don't know whether it is possible without parsing conflict before thorough mulling. It requires a proposer to bring out a viable algorithm.

But before that, think about the ROI of this feature again. It brings many breaking changes. Yet we can still do something like below

type FN0<R> = () => R
type FN1<T1, R> = (t: T) => R
type FN2<T1, T2, R> = (t1: T1, t2: T2) => R
// .....

@pelotom
Copy link

pelotom commented Feb 20, 2017

The requirement to give names to symbols that you will never subsequently use is one of TypeScript's biggest syntactic warts. I think it's worth rectifying even at the expense of breaking changes.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 27, 2017

As noted by @HerringtonDarkholme, this would be a breaking change.

@mhegazy mhegazy closed this as completed Apr 27, 2017
@mhegazy mhegazy added Suggestion An idea for TypeScript Declined The issue was declined as something which matches the TypeScript vision labels Apr 27, 2017
@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
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants