Again, I'm mostly for generics being added to Go, because I've found 
occasion where they would be useful...

On Thursday, July 20, 2017 at 6:40:00 AM UTC-7, M P r a d e s wrote:
>
> Go could have least have parametric functions (ex :
>
> func Foo<T>(value T)T { /.../ }
>
> bar := Foo<int>(3) //types are verified at compile time, no need for 
> reflection or interface {} on any runtime trick.
>
> ).
>

To get at the value of adding generics, knowing what "Foo" is doing is 
important. Presumably, the function operates on "value" in some way.

Can we say that it implements an interface? Then let's suppose the 
existence of an interface "X". I can currently rewrite your "Foo" function 
as:

type X interface {
    Clone() X // documentation needed to clarify that the clone is really 
of the derived type implementing X.
    DoFoo()
}

func Foo(value X) X {
   result := value.Clone()
   result.DoFoo()
   return result
}

Now supposing I have a struct B, where *B implements "X", and is currently 
in variable "orig".

When calling this, to reflect that the result of Foo is still of type *B, 
the following is required.
   fooClone:=(*B).(Foo(orig))

What I want to be able to write, and have *B as the type of "clone":
   fooClone:=Foo(orig)

What we need the function signature to specify, then, is two pieces of 
information, that the parameter "value" is of the same type as its return, 
and that it implements interface "X". Also, my intuition suggests 
distinguishing generic types from concrete ones syntactically, so add an 
indication that's true. Perhaps try a few (+, ^, %).

A bunch of options that all get at the same idea, using different 
characters and different approaches:
func Foo(value T^->X) T^
func Foo(value T%:X) T%
func Foo(value T+:X) T+
func Foo<T^->X>(value T^) T^
func Foo<T%->X>(value T%) T%
func Foo<T+->X>(value T+) T+

where the "->" could really be anything syntactically appropriate, but what 
it means is "T" implements X. Again, not sure of the right syntax, and not 
sure this is required.

In the "X" interface itself, we have a slightly different problem for the 
"Clone" method. We need someway to indicate "the concrete type of the 
thing". For that, we use the syntax indication of a generic type (^, %, or 
+, above) appended to something. "@" seems like a natural fit. That 
probably needs to look something like this:

Clone() @^

Putting it all together, choosing my favorite representation from above:
type X interface {
    Clone() @+
    DoFoo()
}

func Foo(value T+:X) T+ {
   result := value.Clone()
   result.DoFoo()
   return result
}

Now, I can write what I wanted to write:

fooClone := Foo(orig)

There's a *completely separate question* as to whether the compiler 
generates code that is effectively of the form:
fooClone := (*B).(Foo(orig))

I'm not sure I care about that. I'm more concerned about the correctness of 
the code.

Eric.
 

>
> But talking about this is kind of useless until Go rids itself of its over 
> reliance on runtime features like reflection. I suspect Go reflection 
> capabilities are why the language stopped evolving significantly at first 
> place. String tags are another symptom of that "disease".
>
> It's possible to write the snippet above with reflection today 
> (reflect.MakeFunc) , it shouldn't be.
>
>
>

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to