-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Syntax considerations: How we define functions #487
Comments
@sodic super cool issue, I enjoyed reading it and learned a lot :D! I think our mean reason for using arrow functions was that they look cool :D and they feel more functional -> similar to lamdbas in Haskell. But that really comes down to just feel, not utility, as you nicely described above. All together makes sense to me! I think you laid out your arguments very clearly, nothing to add from my side. I will personally try to stick with it if others are for it. So just to clarify, what is then the recommended approach? What I got is:
So is there a situation when |
That's right! But I'd like to emphasize once again that the issue only talks about top-level named function definitions.
We misunderstood each other on this one (my fault, I left it pretty ambiguous). Assuming we implement all our top-level function definitions as statements, we're only left with inline function expressions (and those are mostly one liners). I'd stick with the arrows here. If we ever end up wanting to implement some top-level function definitions as expressions (e.g., the mentioned TypeScript use-case), we can decide what to use then. I could go either way: So, to sum up:
|
This sounds very clear and reasonable! LGTM, and I think you can put this into README under code styles as I mentioned above. |
Will do, assigned myself to the issue! |
Wasp-generated code prefers defining functions as arrow function expressions. The docs suggest the same approach for user-defined Queries and Actions. This issue makes a case on why we should perhaps reconsider this preference.
The dilemma
There are two "dimensions" when it comes to differentiating between function definitions in JavaScript:
Arrow functions statements do not exist, meaning that there are a total of three options: regular-syntax statements, regular-syntax expressions, and arrow-syntax expressions. Out of the three options, the most appropriate way to define a named function seems to be a regular-syntax statement:
While the other two options certainly do have their use cases (e.g., forcing a lexical binding of
this
, shorter inline callbacks, etc.), they seem to be lacking when it comes to defining named functions. I'll do my best to list the advantages and disadvantages of all approaches. Most of the concerns are general, meaning some may not be particularly important for Wasp.Advantages statements have over expressions
const f = function f() { ... }
. This same can't be done with arrow functions, as arrows are always anonymous.function f...
represents a function. Withconst f = function () ...
, not so much.Advantages expressions have over statements
They become pretty handy in TypeScript. Let's suppose we want to define several functions that represent binary operations on numbers. All functions must follow the same interface (in Haskell, this would be
Double -> Double -> Double
).Show example
Function expressions (working together with type inference) reduce code duplication:
Advantages the regular syntax has over the arrow syntax
this
if you don't have to - Arrow functions' most popular semantic feature is the lexical binding ofthis
. Sine we aren't doing anything withthis
in most cases, it's better to opt for a regular function and spare the reader from thinking about irrelevancies.const f = () => ...
is (IMO) even less clear thanconst f = function () ...
. Also, the less non-standard non-alphanumeric characters, the better (controversial for a project written in Haskell, I know :)).Advantages the arrow syntax has over the regular syntax
Verdict
Since modern JavaScript can't exclusively use either syntax (there are cases where we must use arrow function expressions, as well as cases where we must not use them, details here), there will never be a consistent way to define functions across all contexts. Arrow functions will always be more practical for
async
callbacks, but incorrect as methods.With that inherent inconsistency in mind, I suggest our default way of defining named functions becomes regular-syntax statements (it seems to have most going for it). We can then make exceptions to the rule when the need arises (e.g., TypeScript interfaces and decorators).
Assuming we all agree on the approach, it isn't something we must (or even should) start refactoring right away. After all, we have more pressing issues.
The text was updated successfully, but these errors were encountered: