As for me then everything is much more simple if Go language (as the 
starting point) will  introduce a non-reified generics.
Non reified generics does not requires a complex runtime support (static 
code which was generated by the compiler will be enough).
Type checking of the type arguments performed at the compile time on the 
calller side (sender code).
The callee side (receiver code) remains unchanged as it is currently is.
This has some benefits:
1. This is a starting point (but not a no dead end) and point for a later 
enhancements
2. Does not requires significant changes in the compiler (codegen)
3. Does not requires significant changes in the runtime (engine)
4. Does not requires significant changes in the type system (just to add a 
few additional fields into the interface type presentation)
5. Does not requires significant changes in the reflection (just to adapt 
for slightly extended type presentation)

Because they (generic types) will be not reified on the callee side 
(receiver code) then compiler can generate the same code as it generates 
currently.
Only callers side will perform generic type checks before assignments of 
values with generic types and vice versa (to variables, constants, function 
and methods arguments).

That is.

type Foo<K, V> struct {
}

func (s *Foo) Get(key K) (val V) {
  // Here is generated unchanged code
  // The same as for non generic use
}

func some() {
  foo := Foo<string, int>{}

  // Generated by the compiler
  // _typ := _getRTypeOf(foo)
  // _typ.isGeneric = true
  // _typ.genParams = [2]_GenParam
  // _typ.genParams[0] = &_GenParam{key: "K", val: _getRType(interface{}}
  // _typ.genParams[0] = &_GenParam{key: "V", val: _getRType(interface{}}
  // _typ.genArgs = [2]*_RType{}
  // _typ.genArgs[0] = _getRType(string)
  // _typ.genArgs[1] = _getRType(int)
  // Also compiler statically performs type check bounds of the type 
arguments to type parameters assignments (if type bounds specified)

  var key interface{}
  key = bool

  // Generated by the compiler (safe guard)
  // _temp0 := key
  // _checkGenericArg(_typ, 0, temp0)
  // _temp1 := foo.Get(key)

  val := foo.Get(_temp0)
}

That is, the compiler always (if it cannot compute the type at compile time 
and cannot to check them statically) inserts "safe guards" type check 
before any kimd of an assignments.
The `_checkGenericArg(_typ, index, key)` also performs the checks to type 
parameter bounds (eg. for Foo<K string, V int>) for a given index of the 
type parameter and argument.

Callee code does not performs any type checks on incomming parameters.
It always think that incomming parameters has specified type.
That is, if type bounds ommitted then specified type is interface{}
If type bounds specified then specified type is itself

Eg.

type Type1<E> struct {
}

type Type2<E int> struct {
}

func(t *Type1) foo(val E) {
}

func(t *Type2) foo(val E) {
}

Generated as the following (that's easy)

func(t *Type1) foo(val interface{}) {
}

func(t *Type2) foo(val int) {
}

-- 
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