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

proposal: Go 2: currying functions with f{x} and f{arg: x} #66184

Closed
1 of 4 tasks
ezz-no opened this issue Mar 8, 2024 · 7 comments
Closed
1 of 4 tasks

proposal: Go 2: currying functions with f{x} and f{arg: x} #66184

ezz-no opened this issue Mar 8, 2024 · 7 comments
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Milestone

Comments

@ezz-no
Copy link
Contributor

ezz-no commented Mar 8, 2024

Go Programming Experience

Intermediate

Other Languages Experience

No response

Related Idea

  • Has this idea, or one like it, been proposed before?
  • Does this affect error handling?
  • Is this about generics?
  • Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit

Has this idea, or one like it, been proposed before?

No

Does this affect error handling?

No

Is this about generics?

No

Proposal

Allow to construct function composite literal, inside or outside function, to provide a convenient way of constructing named function out of existing function in the case of the only difference is that some arguments differ

Language Spec Changes

Treat function name as type in the case of composite literal

Informal Change

Example:

package main

func f(a int, b int) int {
	return a + b
}

func main() {
	v := 1

	f0 := f{v}
	/*equivalent to
        f0 := func(b int) int {
		f(v, b)
	}*/

	f1 := f{1, 6}
	/* equivalent to
        f1 := func() int {
		return f(1, 6)
	}*/

	f2 := f{b: 3}
	/* equivalent to
        f1 := func(a int) int {
		return f(a, 6)
	}*/

	assertEqual(f(1, 10), f0(10))
	assertEqual(f(1, 6), f1())
        assertEqual(f(2, 3), f2(2))
}

Is this change backward compatible?

Yes

Orthogonality: How does this change interact or overlap with existing features?

No

Would this change make Go easier or harder to learn, and why?

Could understand easily, the concept is well known

Cost Description

Complicate the difficulty of distinguishing function as value or type

Changes to Go ToolChain

Not familiar

Performance Costs

No

Prototype

Types:treat function as type in the case of composite literal
Noder/writer:write down base function object info and fixed arguments
Noder/reader:construct the closure accordingly

@ezz-no ezz-no added LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change labels Mar 8, 2024
@gopherbot gopherbot added this to the Proposal milestone Mar 8, 2024
@Jorropo
Copy link
Member

Jorropo commented Mar 8, 2024

This proposal break the assumption that arguments names are not part of the API.
reflect.Type.In only ever use indexes, in general within the rules of the language there are only positional arguments as far as signatures goes.

It's a backward compatible change, but I don't know if we want something like that.

As an example of why adding meaning to arguments of function looks weird to me:
I think it would be weird if we didn't applied public / private rules on the argument names too.
So:

otherPackage.Foo{b: 6}

shouldn't be allowed imo, for consistency with everything else that use named keys.

I think it's equally weird if we apply public / private rules to argument because what would this do:

// otherpackage.go
func Foo1(B int) {}
func Foo2(b int) {}

// package.go
var a func(b int) = otherPackage.Foo1 // this shouldn't probably fail
var b = a{b: 52}
var c func(B int) = otherPackage.Foo2 // should this fail ? it doesn't currently, and would be breaking change, but it takes a private argument and make it public
var d = c{B: 52} // should this fail ? should the `c =` assignement remember if the original function had public or private arguments, but that a runtime fail

We would also need a syntax like python's /, * to indicate if arguments can be keyed or positional.


Adding argument names to the signature of the function looks like a big can of worms to me, and the value of your proposal is very limited (some syntax sugar), I think this proposal shouldn't be accepted without a more complete story for named arguments as part of the api (like foo(x, y, compare: func(x, y int) int { return cmp(abs(x), abs(y)) }))

@leaxoy
Copy link

leaxoy commented Mar 8, 2024

It's called currying, and it's a very important concept in functional programming, but I don't think the Go team would choose to introduce them.

@seankhliao seankhliao changed the title proposal: Go 2: allow to construct function composite literal proposal: Go 2: currying functions with f{x} Mar 8, 2024
@seankhliao
Copy link
Member

previously #4633 was closed as a dup of #21498

@Jorropo Jorropo changed the title proposal: Go 2: currying functions with f{x} proposal: Go 2: currying functions with f{x} and f{arg: x} Mar 8, 2024
@DeedleFake
Copy link

In Elixir, there's a 'capture operator', &, which lets you turn any expression into a function. It looks like &Example.function("example", &1). This returns a function that takes a single argument and, when called, evaluates that expression, passing in its single argument in place of &1. More arguments can be given, i.e. &2, &3, etc. At least one must be given. Other expressions are allowed besides function calls, too, such as &(&1 + "example"), but my guess is that that could be complicated in Go as it's statically typed.

I don't think it would make sense to overload the & operator in Go, but something else could be used, such as $. I think that's what Swift does.

I'm not necessarily advocating this, but this approach might be cleaner. It separates it from the argument names this way.

@ianlancetaylor
Copy link
Contributor

This amounts to syntactic sugar, since you can already use a function literal. f{v} is equivalent to func(b int) int { return f(v, b) }. So an important question is: how often would real code use this feature? Is it common enough to be worth introducing a new syntax? Especially bearing in mind that the new syntax is somewhat obscure. The difference between using { and ( is subtle.

@ianlancetaylor
Copy link
Contributor

Based on the discussion above, and the emoji voting, this is a likely decline. Leaving open for four weeks for final comments.

@ianlancetaylor
Copy link
Contributor

No further comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

7 participants