Tuesday, September 23, 2014

Go Generics


Go has no support for generic functions, [1], [2]. This makes it hard to write functions that take arguments that change type, because you need to do the heavy-lifting yourself, testing an empty interface, and type assert it to an explicit type. The Go library Gen works around this problem by parsing your code and generating code to do the heavy-lifting. To support generics Gython takes a similar approach.

Gython supports generics by looking at the base class the user has given as the typedef for the first function argument. It then replaces this with an empty interface interface{}, and generates a switch-type block that switches on all the subclasses of the base class, then type asserts and reassigns the variable, and finally copies the function body into each switch-case.

gython input

class A:
 def __init__(self, x:int):
  int self.x = x

 def method1(self) -> int:
  return self.x

class B(A):

 def method1(self) ->int:
  return self.x * 2

class C(A):

 def method1(self) ->int:
  return self.x + 200


def my_generic( g:A ) ->int:
 return g.method1()

def main():
 a = A( 100 )
 b = B( 100 )
 c = C( 100 )

 x = my_generic( a )
 a.x == x

 y = my_generic( b )
 y==200

 z = my_generic( c )
 z==300


gython output

type A struct {
  x int
}
func (self *A)  __init__(x int) {

  self.x = x;
}
func (self *A)  method1() int {

  return self.x
}
func __new__A( x int ) *A {
  ob := A{}
  ob.__init__(x)
  return &ob
}

type B struct {
  A
}
func (self *B)  __init__(x int) {

  self.x = x;
}
func (self *B)  A_method1() int {

  return self.x
}
func (self *B)  method1() int {

  return (self.x * 2)
}
func __new__B( x int ) *B {
  ob := B{}
  ob.__init__(x)
  return &ob
}

type C struct {
  A
}
func (self *C)  __init__(x int) {

  self.x = x;
}
func (self *C)  A_method1() int {

  return self.x
}
func (self *C)  method1() int {

  return (self.x + 200)
}
func __new__C( x int ) *C {
  ob := C{}
  ob.__init__(x)
  return &ob
}

func my_generic(__gen__ interface{}) int {

  switch __gen__.(type) {
    case *A:
      g,_ := __gen__.(*A)
      return g.method1()
    case *C:
      g,_ := __gen__.(*C)
      return g.method1()
    case *B:
      g,_ := __gen__.(*B)
      return g.method1()
  }
  return 0
}

func main() {

  a := __new__A(100);
  b := __new__B(100);
  c := __new__C(100);
  x := my_generic(a);
  ( a.x ) == x
  y := my_generic(b);
  ( y ) == 200
  z := my_generic(c);
  ( z ) == 300
}

No comments:

Post a Comment