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

Passing arguments to the function #9

Closed
jridgewell opened this issue May 7, 2018 · 12 comments · Fixed by #16
Closed

Passing arguments to the function #9

jridgewell opened this issue May 7, 2018 · 12 comments · Fixed by #16

Comments

@jridgewell
Copy link
Member

jridgewell commented May 7, 2018

When linting for the old pattern in the AMP codebase, I'm frequently finding that the call expressions take parameters:

return Promise.resolve(fn(arg))

To requires a lot of either binding, or wrapping the function in an arrow closure. Would it be more performant for implementations to take these parameters in the call to Promise.try?

// variadic args after the fn
return Promise.try(fn, arg);
@ljharb
Copy link
Member

ljharb commented May 7, 2018

I'm not sure if the complexity is warranted; I think generally the performance of wrapping in an arrow function is pretty much the same as not. Worth thinking about tho!

@jridgewell
Copy link
Member Author

For reference, here's the PR in AMP. Frequently, it's just a single param that's needed, though sometimes I need to capture this context, too. So, passing the needed params wouldn't solve everything.

@semmel
Copy link

semmel commented Apr 5, 2019

When programming in functional style I rarely encounter nullary functions (without arguments). So at first I'd agree for the need to have arguments (and don't care about this 😃 ).

On the other hand, if Promise.try(f) is just like Promise.resolve(f()), without the additional JS execution tick, would one not loose composability and thus declarative style?
Even if Promise.try were to accept variadic arguments:

// for brevity just unary functions
var compose = f => g => x => f(g(x));

var h = compose(f, compose(Promise.resolve.bind(Promise), g)); // defining the function pipeline
h(x); // executing later

var h = compose(f, Promise.try.bind(Promise, g, x)) //  defining the function pipeline
h(); // no way to specify the arguments at runtime

Maybe I am wrong, but in this light I don't find Promise.try useful with or without arguments.
🤔

@syg
Copy link

syg commented Feb 7, 2024

Frequently, it's just a single param that's needed, though sometimes I need to capture this context, too.

When you need to do that, you can use an arrow. But when you don't, you avoid creating a closure just to forward arguments. I don't see any downside really to forward ...arguments. In the default case of not passing any arguments the API is the same. Where's the complexity?

@ljharb ljharb mentioned this issue Feb 7, 2024
29 tasks
@ljharb
Copy link
Member

ljharb commented Feb 7, 2024

@syg what about a receiver/thisArg for the callback?

@syg
Copy link

syg commented Feb 7, 2024

@syg what about a receiver/thisArg for the callback?

My preference is to just not have support for forwarding the receiver. I feel like you can take a thisArg if it's the only thing to forward, otherwise there's no good place to put it (first? last?) and it makes the API much more messy.

@bakkot
Copy link

bakkot commented Feb 7, 2024

Given that the stated use case is "someone gives you a function to call", I don't think there's a need to support providing a this. It's reasonable to have a passed-in callback which you invoke with some arguments, but it's much rarer to have a user-provided method which you need to invoke with a specific this binding.

@ljharb
Copy link
Member

ljharb commented Feb 7, 2024

I agree, it’s just that supporting arguments raises that question imo.

Do we accept arguments to pass, modulo thisArg, anywhere else in the language that takes a callback?

@ljharb
Copy link
Member

ljharb commented Feb 7, 2024

What's the complexity?

spec-wise, none - I put up #16 as a draft to discuss, which is a trivial change.

@bakkot
Copy link

bakkot commented Feb 7, 2024

Do we accept arguments to pass, modulo thisArg, anywhere else in the language that takes a callback?

This is less "taking a callback" and more "wrapping a callback". Most places that take a function do so because they're expecting a specific format of function to serve a specific role - like the predicate argument to filter, say. This case isn't like that: it's fully agnostic to what the function is, because the intention is that it is used as, basically, a special way of calling a function, rather than because it's actually doing something with the function.

So the closest analogies are Function.prototype.{call,apply}, which are also just special ways of calling a function. Those cases do provide a this in addition to arguments, but that's because providing a this is a large part of what those are for, so I don't think we need to carry forward that particular aspect.

@ljharb
Copy link
Member

ljharb commented Feb 7, 2024

That's a decently persuasive answer to the question, thanks.

@jridgewell
Copy link
Member Author

Do we accept arguments to pass, modulo thisArg, anywhere else in the language that takes a callback?

AsyncContext's Snapshot.p.run and Variable.p.run both follow this pattern of forwarding args. Our (potential) Snapshot.wrap will also forward.

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

Successfully merging a pull request may close this issue.

5 participants