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

Function signature convention #3

Closed
alexandru opened this issue Feb 6, 2018 · 5 comments
Closed

Function signature convention #3

alexandru opened this issue Feb 6, 2018 · 5 comments

Comments

@alexandru
Copy link

alexandru commented Feb 6, 2018

On function signatures, currently the convention in static-land is that of Haskell, where the value that is being transformed (this in Fantasy-Land) happens last, for example:

chain<A, B>(f: (a: A) => F<B>, fa: F<A>): F<B>

This makes a lot of sense in ML languages, due to currying and partial application actually working. However for an OOP language that doesn't do currying like in ML, this convention is not user-friendly, because people expect that parameter to happen first, as in:

chain<A, B>(fa: F<A>, f: (a: A) => F<B>): F<B>

This is the convention used in Cats (sample), Scalaz (sample) for Scala and Arrow (sample) for Kotlin.

Personally I doubt that currying is used much in the wild, but that's just a hunch, maybe somebody can correct me. The language actively fights against partial application. Even further, even if functions are indeed values, the language fights against passing functions around as values (e.g. the array.map(parseInt) mess). Plus tricks via overloading call are not easy to type and you also have problems with default arguments.

In my opinion, if currying isn't a really strong argument, the second convention is much more natural because it's how we are hardwired by OOP's single dispatch.

@gcanti
Copy link

gcanti commented Feb 6, 2018

FYI in TypeScript the order of arguments matters a lot with respect to type inference since they are processed from left to right. In the next version of fp-ts many signatures will be changed in accordance with this proposal so that you get more help / suggestions from the type checker / quick info.

Reference: gcanti/fp-ts#290 (comment)

@rpominov
Copy link
Member

rpominov commented Feb 6, 2018

I personally don't use currying usually. I wait for https://github.com/tc39/proposal-partial-application to land, and for now prefer to use arrow functions for partial application ((_) => foo(_, 1, 2)). Both of these don't care about arguments order, so I don't have a strong opinion on this one. Except for the tendency to avoid any breaking changes. But if we'll have many new ideas and therefore many changes, having this one may not be a problem.

Also this might be related fantasyland/static-land#6

@alexandru
Copy link
Author

alexandru commented Feb 8, 2018

I'm all for avoiding breaking changes, however consider that this proposal breaks compatibility for Fantasy-Land, which by the looks of it is the more popular specification and that the transition from:

obj.chain(f)

Is easier if we do:

F.chain(obj, f)

Then if we do:

F.chain(f, obj)

And @gcanti is right above — even though I noticed TypeScript can handle the type inference in many cases, usually type inference happens from left to right. So if there's ever a time to break compatibility on this one, it's now imo.

@rpominov
Copy link
Member

rpominov commented Feb 8, 2018

Right, there will be huge compatibility break compared to Fantasy Land. But, libraries that already implement Static Land may get compatibility with the new specification almost for free. We have a list of such libraries https://github.com/rpominov/static-land/wiki/Compatible-libraries , also some libraries happen to be compatible with Static Land order even though API was designed before Static Land was published. For example, https://github.com/cujojs/most had static methods with exactly right signatures. Also, http://ramdajs.com/ may be considered as a Static Land module that dispatches to Fantasy Land methods (not sure how practical it would be to use it that way, but API matches exactly). Btw, Ramda users probably will be very disappointed with this change.

Also, I'm not sure about ease of transition argument. The currying friendly order is very popular and familiar in JavaScript FP community. But the argument about TypeScript seems important.

@alexandru
Copy link
Author

alexandru commented Feb 8, 2018

I see, these are good arguments @rpominov.

Well, to be honest, the TypeScript argument isn't that important, my only requirement would be for TypeScript types to be possible and I haven't gone through the whole list of type classes yet to know for sure, but in case of map, chain and chainRec, while weird for me, TypeScript is still OK.

To avoid issues lingering on forever, I'm closing this for now, if anybody can bring up other arguments or show more support, we can re-open the discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants