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: mini-package: a solution to unify Go builtin and custom generics #32895

Open
dotaheor opened this issue Jul 2, 2019 · 14 comments

Comments

@dotaheor
Copy link

commented Jul 2, 2019

https://github.com/dotaheor/unify-Go-builtin-and-custom-generics/blob/master/README.md

The proposal introduces a gen code element concept which is much like our familiar func element concept, which makes the proposal very easy to understand.

@gopherbot gopherbot added this to the Proposal milestone Jul 2, 2019

@gopherbot gopherbot added the Proposal label Jul 2, 2019

@rsc

This comment has been minimized.

Copy link
Contributor

commented Jul 2, 2019

For what it's worth, I don't understand exactly what the proposal means, nor how to implement it.

@rsc rsc added the Go2 label Jul 2, 2019

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 3, 2019

I don't understand how to write the Min function using this approach: the function that takes two values of any ordered type and returns the smaller value.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 3, 2019

@rsc This proposal is very rough. There must be many flaws and logic problems in it. Hope it will inspire someone to get a better Go generic design idea.

Basically, this proposal tries to decouple the generic parameter declaration part and the function/type implementation parts, so that main generic body code still keeps looking as Go 1 style and a better readability is got. (I really don't like the cumbersome feeling in the syntax designs of C++/Java/Rust, especially their generic designs.)

I don't have an idea on how to implement it too (if even if you neither, ;D). Maybe it can be implemented in a 3rd-party code generation tool, but I think the experience will be smoother when implementing it as a builtin feature.

@ianlancetaylor The Min generic function can be simply written as

// A gen also acts as a contract at the same time.
gen Min[T type] func {
	export func(x, y T) T {
		if x < y {
			return x
		} else {
			return y
		}
	}
}

Use it:

var n = Min[int32](11, 9)             // n == 9, type of n is int32
var t = Min[string]("hello", "world") // t == "hello", type of t is string
var b = Min[bool](true, false)        // compilation error

// Or, we can bind the generic export to some func declarations.
func MinInt32 = Min[int32]
func MinString = Min[string]
var n1 = MinInt32(11, 9)
var t1 = MinString("hello", "world")

// The code will be simpler by making use of type deduction.
var n2 = Min(11, int32(9))
var t2 = Min("hello", "world")
@fbnz156

This comment has been minimized.

Copy link

commented Jul 4, 2019

@dotaheor Have you considered looking at code generation for this? See this: https://github.com/ncw/gotemplate

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 4, 2019

@fabian-f Your project is cool, but it looks it only works well for some data struct use cases. A general generic solution will support more variations.

I ever had a similar idea by using type alias in a package as generic inputs. I planed to use .gg as generic Go file extensions and write a generator program scan all the *.gg files to translate to them as *.go files. But I didn't find a design with a smooth experience, so I gave up it.

@fbnz156

This comment has been minimized.

Copy link

commented Jul 4, 2019

@dotaheor it's not actually my project.

I actually typed something similar to what you're describing but decided not to suggest it. Generics as you describe them would be too dramatic of a change for Go, and amounts to simple templating.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 4, 2019

This proposal is really some like C++ template. I don't want to defend C++ template design, but I think C++ template design is not all bad. In fact, many C++ template uses are very readable. The problem of C++ templates is just that it enables people write strange-looking and hard-to-read (and hard-to-debug) code.

This proposal has a distinct characteristic from C++ template design: the exported function/type declaration code parts never entangle with any new added generic element parts. This effectively protects the readability of Go 1 code.

I admit this proposal is some dramatically to change Go, but I think the fact that the newly introduced gen code element concept is much like our familiar func element concept makes the proposal easy to understand.

@fbnz156

This comment has been minimized.

Copy link

commented Jul 4, 2019

@dotaheor At the end of the day this proposal is still just code templating, which would be much better achieved with a pre-processor (//go:generate) than by modifying the compiler and language spec to effectively achieve the same thing.

I would love generics as much as anyone but there's been no decent suggestions on how to achieve them without complicating Go significantly. This gen keyword proposal is no different.

Perhaps a sensible suggestion would be for an all purpose code preprocessor, which would allow for domain-specific syntax to be added and reduce endless arguing over language changes. This would allow you to create templating using your syntax, generate and substitute typenames.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 4, 2019

@fabian-f This proposal is just an idea. It is far to be practicable to be implemented as a formal Go syntax set yet. It is presented here is mainly for inspiration purpose.

Personally, I just think this proposal idea is interesting and is easy to understand. It can be viewed as an attempt to standardize all kinds of code generators, in the familiar function declaration and call manner, to solve some common problems in Go for lacking of custom generics.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 10, 2019

There are a lot of different ideas here, and I think they need more explanation. How many new keywords does this add? What does on absent do? What is a "builtin generic privilege"? What does it mean for a gen to return an import? How do operator generics work--which operators are permitted? What happens if the arguments to a generic operator have different types? Why the builtin contract comparable? Are there any other builtin contracts?

In the generics design draft contracts serve two purposes: they describe acceptable type arguments and they define permitted operations. It's not really clear whether they serve the same roles in this proposal.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 10, 2019

There should be two new keywords for sure: gen and export. The on absent is just for description convenience purpose. There should be better alternative ways to do the same job.

For "builtin generic privilege", I mean this current proposal doesn't unify builtin generics and custom generics perfectly. Builtin generics still have some privileges which custom generics can't get.

Please note that this proposal just tries to make the docs of builtin generics look consistent with custom generics. The current builtin generics implementation needn't to be changed.

What does it mean for a gen to return an import?

We can view this as a sub/mini-package is exported as an import, so the result can be assigned to an import identifier, then we can use the import identifier as qualified prefix like the current non-generic imports. When a gen exports hybrid element kinds, such as functions and types, this is a recommended alternative way to let the gen export one result instead.

How do operator generics work--which operators are permitted? What happens if the arguments to a generic operator have different types?

Generally, the types of the arguments should not be different, which is indicated by the example operator gen (the gen itself also acts as a contract).

Maybe the optional inputs and operator generics features mentioned in the proposal are not good ideas.

Why the builtin contract comparable? Are there any other builtin contracts?

I think sometimes named contracts have better readabilities. I tried to list potential useful builtin contracts here: https://gist.github.com/dotaheor/a746923b46d2514ceef49cb47958fd71 (please ignore the assure keyword used there)

In the generics design draft contracts serve two purposes: they describe acceptable type arguments and they define permitted operations. It's not really clear whether they serve the same roles in this proposal.

Yes, this proposal tries to serve the same roles. The difference from the draft is it combines the contract and generic function/type definition syntax in draft as one gen block.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 27, 2019

@ianlancetaylor In fact, the export keyword is also not very essential. We can comply with the current Go conventions. If a gen only exports one type or func element, then there can only be exactly one type or function which is declared as exported (first letter is upper case) in the gen body. If a gen exports an import, then there can be multiple elements declared as exported.

@dotaheor

This comment has been minimized.

Copy link
Author

commented Jul 27, 2019

I forgot mentioning that the design in the last comment requires each gen has at most one output. So types and functions hybrid outputs will be prohibited.

BTW, I rewrote the examples in this CL (https://go-review.googlesource.com/c/go/+/187317) with the styles of the proposal in this issue.

Some small changes are added to simplify some simple single output gens.

@dotaheor dotaheor changed the title proposal: Go 2: Generic is gen: super function - a solution to unify Go builtin and custom generics proposal: Go 2: mini-package: a solution to unify Go builtin and custom generics Jul 30, 2019

@dotaheor

This comment has been minimized.

Copy link
Author

commented Aug 2, 2019

I added a rule in the end of the proposal to make the unification complete reluctantly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.