[Generics] Simplified syntax to sidestep the bracket arguments

154 views
Skip to first unread message

Kh Af

unread,
Jul 21, 2020, 12:51:21 PM7/21/20
to golang-nuts
Forgive me for making a new thread, I felt the older ones had run their course, and I had trouble deciding who to reply to.

I would like to propose a simpler syntax which looks a bit more Go-like (to me)
is more terse, has no ambiguity and does not require any new bracket types. Here it goes:

// generic type variables are always prefixed by an `@` symbol
type Heap(@T) struct {
    data []@T
    head, tail uint
}

// this is how it is instantiated:
var myHeapInt Heap@(int)
var myHeapSomeType Heap@(SomeType)

// No need to specify the type variable in functions, they should just match the declaration.
// Easy for the compiler and humans to follow. There's practically no new syntax other
// than the generic type specifier.
func (h *Heap) Push(v @T) bool {
    ...
}

// Complex example with multiple type specifiers.
// What if one wants explicit order of instantiation?
type S(@V, @U, @T) struct {
    P1 @T
    P2 @U
    P3 @V
}

// instantiation is always the same syntax
var myS S@(int, string, float)

// what if attributes are of generic type themselves?
// This equates to: S2<S<T, U V>>
// which can be simplified to S2<T, U, V> where S<T, U, V> exists
type S2(@T, @U, @V) struct {
    P1 S(@T, @U, @V)
}

// can be instantiated the usual way
var myS2 S2@(int, string, float)

// for a function, which constraints are set for the input types
func Max(v ...@T) @T
where @T: int | uint | int8 | ... | float32 | float64, // T can be of multiple types, which helps to avoid defining a new interface for everything
// @V : ... multiple where clauses can be added here for different type variables
{
    ...
}

////////////////////////////////////////////////////////////////
//
// Examples lifted from the official proposal:
//
////////////////////////////////////////////////////////////////

// Smallest returns the smallest element in a slice.
// It panics if the slice is empty.
func Smallest(s []@T) @T
where @T: Ordered
{
    r := s[0] // panics if slice is empty
    for _, v := range s[1:] {
        if v < r {
            r = v
        }
    }
    return r
}

// Map calls the function f on every element of the slice s,
// returning a new slice of the results.
func Map(s []@F, f func(@F) @T) []@T {
    r := make([]@T, len(s))
    for i, v := range s {
        r[i] = f(v)
    }
    return r
}

// NewPair returns a pair of values of the same type.
func NewPair(f1, f2 @F) *Pair(@F) { ... }

To me this looks simpler and more clear to read than the official proposal, and practically all other generics syntax that I know of.
The `@` symbol will immediately signal `generic type` to the reader, there isn't too much to type, retype or read.
You will also never see a generic type without its `@` prefix anywhere in the code, which significantly helps with readability.
It's vague neither to humans nor machines, and can be read as `Heap at int (-land!)` during instantiation which while not
idiomatic English, still communicates the purpose.

What do you think?


Ian Lance Taylor

unread,
Jul 21, 2020, 6:42:05 PM7/21/20
to Kh Af, golang-nuts
Just some quick notes.

The @ character seems to move from declaration to instantiation. In
the declaration it's a prefix for a type parameter, in an
instantiation it introduces a list of type arguments.

The "where" clause used for constraints is like nothing else in Go.

Using an @ prefix for some identifiers isn't like anything else in Go.
In Go all identifiers other than labels share the same namespace and
are written the same way.

Ian

robert engels

unread,
Jul 21, 2020, 7:17:07 PM7/21/20
to Kh Af, golang-nuts
I think this has merit. “Feels” Go-Like to me and is very easy to read.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/a06922a0-c6c5-4ca4-924a-cc9337cb01b9o%40googlegroups.com.

Andrey T.

unread,
Jul 22, 2020, 12:39:27 AM7/22/20
to golang-nuts
I have tried to propose something like this in
https://groups.google.com/forum/#!topic/golang-nuts/W3fSnH0w1G0 (and earlier I was dancing around that idea in https://groups.google.com/forum/#!topic/golang-nuts/Rp3yUUy2nS8 ), but somehow it did not get any serious attention.

I still think that @, $ or # or could be an interesting approach, be that spiritually following ' (apostrophe) in Lisp, or * (star) as a pointer to a type T to be read $T as "meta-T"

Thanks,
  Andrey
Reply all
Reply to author
Forward
0 new messages