Skip to content

Instantly share code, notes, and snippets.

@pborman
Last active September 11, 2018 23:08
Show Gist options
  • Save pborman/a6958ee6b7d6668e35fc99db07ea29e4 to your computer and use it in GitHub Desktop.
Save pborman/a6958ee6b7d6668e35fc99db07ea29e4 to your computer and use it in GitHub Desktop.
Yet another simplification proposal for generics in Go

I have found the generics syntax to be somewhat confusing, too many things look the same and there seem to be too many names involved. I admit I have not been reading all of the suggestions (I simply do not have that much spare time), so forgive me if this has already been proposed.

Start with one of the examples:

	contract viaStrings(t To, f From) {
  		var x string = f.String()
   		t.Set(string("")) // could also use t.Set(x)
	}

What is the point of t and f? Why not simply:

	contract viaStrings(To, From) {
  		string = From.String()
   		To.Set(string)
	}

When using a contract, we have too many ()’s. How about something that doesn’t require as much context to figure out:

	func SetViaStrings[bar(A, B)](s []B) []A { … }

Then when using:

	var ips []net.IP
	a := SetViaStrings[_, []string](ips)

The _ means you can infer the type from the call. If all types can be inferred, as in the proposal:

	var ips []net.IP
	var a []string
	a = SetViaStrings(ips)

I also sort of see a contract as a type, so I would consider:

	type viaStrings(t To, f From) contract { … }

Note that this is the only place the term contract needs to be used. There is no reason it needs to be an explicit keyword.

Extending the simplified syntax (I have seen other similar suggestions), assuming all single upper case letters are contract types for demonstrative purposes (e.g., contract Foo(A, B, C))

	A.(int)                 // A is assignable to an int
	A.(B)                   // A is assignable to B
	error = A.Foo(B, C)     // A has a method Foo that takes a B and C and returns an error
	B, error = A(B, C, int) // A is a function that takes a B, C, and an int, returning a B and an error
	nil = A                 // A can be nil
	error = A               // A implememnts the error interface
	!A                      // A is boolean
	A == A                  // A supports equality
	A < A                   // A supports inequality
	A + A                   // A supports addition
	A * A                   // A supports arithmetic oprations
	A % A                   // A supports modulus
	A[:]                    // A is a slice (maybe just A[])
	C = A[B]                // A is a map of B to C
	_ = A[B]                // A is a map of B to anything (maybe just A[B])
	B = <- C                // C is a channel of B
	<- C                    // C is a channel of anything
	len(A)                  // A has length
	cap(A)                  // A has capacity

That list is probably not exhaustive, but it should be straightforward to extend. The key is that there are no loops, conditions, range statements, etc. It probably requires more work on the parser, but we are optimizing the person reading the source code, right?

Anyhow, I am certainly more in favor of the contract being a series of single lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment