-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Receiver-like function calls #58589
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
Comments
A similar proposal #56283, was made and rejected before how would this solve the problems raised in that proposal?. |
I see. From the linked, similar proposal, I understand that the remaining issue (the one which cannot be solved by using an invocation operator different than dot), is:
In that case, maybe a Kotlin-like explicit definition of receiver functions (not methods) would help. For example: func (is Slice[I])::Map[I, O any](f func(I) O) Slice[O] {
var os Slice[O]
for i := range is {
os = append(os, f(is[i]))
}
return os
} (Notice the Defining it that way, you would prevent adding extension functions to existing types unless you define a new type containing them (just exactly as you do for adding methods to a type): // illegal
func (i int)::Plus(o int) int { return i + o }
// legal
type Num int
func (i Num)::Plus(o Num) int { return i + o } That would probably fit better within the Go design philosophy, not having duplicate grammars for the same action. That restriction would also allow e.g. checking that two libraries aren't defining a method and a receiver-like functions with the same name. That would also avoid requiring to specify the package name when invoking the function. |
@mariomac ISTM that the "receiver functions" you suggest are only differentiated from methods, by a) a slight syntactic difference and b) no interface satisfaction. In #49085, the main argument against adding methods with type parameters which do not satisfy interfaces was that it doesn't seem to clear the bar of usefulness, for mere syntactic convenience. ISTM that this proposal has the same syntactical convenience as a goal and so it has to make pretty much the same tradeoff. The tradeoff changes a little bit by shifting the downsides from "some methods don't satisfy interfaces" to "some methods look slightly different and are called receiver functions" - but that doesn't seem like a material change. And it comes at the additional cost of introducing a new token to the language. I also personally consider the most salient argument from #56283 not to be the tab-completion issue, but this one. |
Goal: be able to implement method-like function calls without the implications
of methods (e.g. not defining an "implements" relation to any interface). This
new language feature would be just syntactic sugar for function
invocations, allowing to place the first argument of a function right before the
function name, so the following invocations would be exactly equivalent:
Please observe that this proposal would require a new operator to use the first
function argument as a receiver (for, example,
::
).Related work
The idea of receiver-like function calls is already present in the Kotlin language:
https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver
https://kotlinlang.org/docs/extensions.html
They are just function calls where an argument is specified as a receiver. The main
differences with the proposal here are:
is similar to the actual Go methods' definition. The proposal here does not introduce
any new form of function signature.
dot operator, while this proposal suggests adding a different operator (for example
::
)to differentiate the new receiver-like invocation of a function from the actual method
invocations.
Use case: fluent concatenation of generic functions
Let's describe the following
Slice[I]
generic type and theMap[I, O]
functionthat applies a function
f: I --> O
to the inputSlice[I]
and returns anew
Slice[O]
, where the typesI
andO
could differ:If we want to perform several map operations:
Because of the aspects discussed in #49085,
it is not possible to define
Map
as a method, so a fluent concatenation ofmultiple
Map
invocations would require using a form like:However, using receiver-like function calls would allow us concatenate functions
in a readable manner without needing to create intermediate variables:
The text was updated successfully, but these errors were encountered: