class A[TA,TB,TC]: a: TA b: TB c: TC def dump(a, b, c): print a, b, c # non-generic method: def m0(self: A[TA,TB,TC], a: int): print a # basic generics: def m1[X](self: A[TA,TB,TC], other: A[X,X,X]): print other.a, other.b, other.c # non-generic method referencing outer generics: def m2(a: TA, b: TB, c: TC): A.dump(a, b, c) # generic args: def m3(self, other): return self.a # lots of nesting: def m4[TD](self: A[TA,TB,TC], d: TD): def m5[TA,TB,TC,TD,TE](a: TA, b: TB, c: TC, d: TD, e: TE): print a, b, c, d, e m5(self.a, self.b, self.c, d, d) # instantiating the type: def m5(self): x = A(self.a, self.b, self.c) A.dump(x.a, x.b, x.c) # deeply nested generic type: def m6[T](v: array[array[array[T]]]): return v[0][0][0] # explicit realization: def m7(T: type, S: type): print "works" class B1[T]: a: T def foo[S](self: S) -> B1[int]: return B1[int](111) class B2[T]: a: T def foo[S](self: B2[S]): return B2[int](222) a1 = A(42, 3.14, "hello") a2 = A(1, 2, 3) b1 = B1[bool](True).foo() b2 = B2[str]("x").foo() v1 = array[array[array[str]]](1) v2 = array[array[str]](1) v3 = array[str](1) v1[0] = v2 v2[0] = v3 v3[0] = "world" f = a2.m0 a1.m1(a2) # EXPECT: 1 2 3 A[int,float,str].m2(1, 1.0, "one") # EXPECT: 1 1 one A[int,int,int].m2(11, 22, 33) # EXPECT: 11 22 33 print a1.m3(a2) # EXPECT: 42 print a1.m3(a2) # EXPECT: 42 print a2.m3(a1) # EXPECT: 1 a1.m4(True) # EXPECT: 42 3.14 hello True True a1.m4([1]) # EXPECT: 42 3.14 hello [1] [1] a2.m4("x") # EXPECT: 1 2 3 x x a1.m5() # EXPECT: 42 3.14 hello a2.m5() # EXPECT: 1 2 3 print A.m6(v1) # EXPECT: world m7(str,float) # EXPECT: works m7(str,float) # EXPECT: works m7(float,str) # EXPECT: works f(99) # EXPECT: 99 print b1.foo().a # EXPECT: 111 print b2.foo().a # EXPECT: 222 # recursive generics with different inner type parameter def foo(a): if not a: foo(True) print a # EXPECT: True # EXPECT: 0 foo(0) def bar(a): def baz(x): if not x: bar(True) print(x) baz(a) # EXPECT: True # EXPECT: 0 bar(0)