Merge tests into a larger file (part 1 of ∞) (#9318)

* merge actiontable tests

* merge arithm tests

* merge array tests

* merge assign tests

* merge bind tests

* merge casestmt tests

* merge closure tests

* merge cnt seq tests

* merge collections tests

* merge concept issues tests

* merge concept tests

* fix failing tests

* smaller outputs

Use `doAssert` where possible.

* fix wrong output

* split `tcomputedgoto`

* revert merging concepts

* fix failing test
This commit is contained in:
Miran 2018-10-12 17:02:46 +02:00 • committed by Andreas Rumpf
commit 7f18d7cbc1
103 changed files with 3736 additions and 3368 deletions

View file

@ -1,21 +0,0 @@
discard """
output: "true\ntrue"
"""
type
TFooContainer[T] = object
TContainer[T] = concept var c
foo(c, T)
proc foo[T](c: var TFooContainer[T], val: T) =
discard
proc bar(c: var TContainer) =
discard
var fooContainer: TFooContainer[int]
echo fooContainer is TFooContainer # true.
echo fooContainer is TFooContainer[int] # true.
fooContainer.bar()

View file

@ -1,22 +0,0 @@
type
View[T] = concept v
v.empty is bool
v.front is T
popFront v
proc find(view: View; target: View.T): View =
result = view
while not result.empty:
if view.front == target:
return
mixin popFront
popFront result
proc popFront[T](s: var seq[T]) = discard
proc empty[T](s: seq[T]): bool = false
var s1 = @[1, 2, 3]
let s2 = s1.find(10)

View file

@ -1,25 +0,0 @@
discard """
output: 9
"""
type DataTable = concept x
x is object
for f in fields(x):
f is seq
type Students = object
id : seq[int]
name : seq[string]
age: seq[int]
proc nrow*(dt: DataTable) : Natural =
var totalLen = 0
for f in fields(dt):
totalLen += f.len
return totalLen
let
stud = Students(id : @[1,2,3], name : @["Vas", "Pas", "NafNaf"], age : @[10,16,32])
echo nrow(stud)

View file

@ -1,26 +0,0 @@
discard """
output: '''
true
true
true
f
0
'''
"""
import t5888lib/ca, t5888lib/opt
type LocalCA = ca.CA
proc f(c: CA) =
echo "f"
echo c.x
var o = new(Opt)
echo o is CA
echo o is LocalCA
echo o is ca.CA
o.f()

View file

@ -1,20 +0,0 @@
discard """
exitcode: 0
"""
type
Enumerable[T] = concept e
for it in e:
it is T
proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
result = @[]
for it in e: result.add(fn(it))
import json
var x = %["hello", "world"]
var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
assert z == @["hello!", "world!"]

View file

@ -1,22 +0,0 @@
discard """
output: "20.0 USD"
"""
import typetraits
const currencies = ["USD", "EUR"] # in real code 120 currencies
type USD* = distinct float # in real code 120 types generates using macro
type EUR* = distinct float
type CurrencyAmount = concept c
type t = c.type
const name = c.type.name
name in currencies
proc `$`(x: CurrencyAmount): string =
$float(x) & " " & x.name
let amount = 20.USD
echo amount

View file

@ -1,23 +0,0 @@
discard """
output: "true"
"""
import future
type
FilterMixin*[T] = ref object
test*: (T) -> bool
trans*: (T) -> T
SeqGen*[T] = ref object
fil*: FilterMixin[T]
WithFilter[T] = concept a
a.fil is FilterMixin[T]
proc test*[T](a: WithFilter[T]): (T) -> bool =
a.fil.test
var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
echo s.test() == nil

View file

@ -1,27 +0,0 @@
discard """
output: '''
10
10
'''
"""
type GA = concept c
c.a is int
type A = object
a: int
type AA = object
case exists: bool
of true:
a: int
else:
discard
proc print(inp: GA) =
echo inp.a
let failing = AA(exists: true, a: 10)
let working = A(a:10)
print(working)
print(failing)

View file

@ -1,12 +0,0 @@
discard """
output: 5
"""
type
HasLen = concept iter
len(iter) is int
proc echoLen(x: HasLen) =
echo len(x)
echoLen([1, 2, 3, 4, 5])

View file

@ -1,16 +0,0 @@
discard """
output: "()"
"""
type
Iterable[T] = concept x
for elem in x:
elem is T
proc max[A](iter: Iterable[A]): A =
discard
type
MyType = object
echo max(@[MyType()])

View file

@ -1,54 +0,0 @@
discard """
output: '''Printable'''
"""
import macros
type
int1 = distinct int
int2 = distinct int
int1g = concept x
x is int1
int2g = concept x
x is int2
proc take[T: int1g](value: int1) =
when T is int2:
static: error("killed in take(int1)")
proc take[T: int2g](vale: int2) =
when T is int1:
static: error("killed in take(int2)")
var i1: int1 = 1.int1
var i2: int2 = 2.int2
take[int1](i1)
take[int2](i2)
template reject(e) =
static: assert(not compiles(e))
reject take[string](i2)
reject take[int1](i2)
# bug #6249
type
Obj1[T] = object
v: T
Obj2 = ref object
PrintAble = concept x
$x is string
converter toObj1[T](t: T): Obj1[T] =
return Obj1[T](v: t)
proc `$`[T](nt: Obj1[T]): string =
when T is PrintAble: result = "Printable"
else: result = "Non Printable"
echo Obj2()

View file

@ -0,0 +1,441 @@
discard """
file: "tconcepts.nim"
output: '''
10
20
int
20
3
x as ParameterizedType[T]
x as ParameterizedType[T]
x as ParameterizedType[T]
x as ParameterizedType
x as ParameterizedType
x as CustomTypeClass
1
2
3
4
5
6
a
b
t
e
s
t
z
e
1
2
3
20
10
5
'''
"""
import typetraits, strutils
block tcomparable:
type
Comparable = concept a
(a < a) is bool
proc myMax(a, b: Comparable): Comparable =
if a < b:
return b
else:
return a
doAssert myMax(5, 10) == 10
doAssert myMax(31.3, 1.23124) == 31.3
block tconceptinclosure:
type
FonConcept = concept x
x.x is int
GenericConcept[T] = concept x
x.x is T
const L = T.name.len
Implementation = object
x: int
Closure = object
f: proc()
proc f1(x: FonConcept): Closure =
result.f = proc () =
echo x.x
proc f2(x: GenericConcept): Closure =
result.f = proc () =
echo x.x
echo GenericConcept.T.name
proc f3[T](x: GenericConcept[T]): Closure =
result.f = proc () =
echo x.x
echo x.L
let x = Implementation(x: 10)
let y = Implementation(x: 20)
let a = x.f1
let b = x.f2
let c = x.f1
let d = y.f2
let e = y.f3
a.f()
d.f()
e.f()
block overload_precedence:
type ParameterizedType[T] = object
type CustomTypeClass = concept
true
# 3 competing procs
proc a[T](x: ParameterizedType[T]) =
echo "x as ParameterizedType[T]"
proc a(x: ParameterizedType) =
echo "x as ParameterizedType"
proc a(x: CustomTypeClass) =
echo "x as CustomTypeClass"
# the same procs in different order
proc b(x: ParameterizedType) =
echo "x as ParameterizedType"
proc b(x: CustomTypeClass) =
echo "x as CustomTypeClass"
proc b[T](x: ParameterizedType[T]) =
echo "x as ParameterizedType[T]"
# and yet another order
proc c(x: CustomTypeClass) =
echo "x as CustomTypeClass"
proc c(x: ParameterizedType) =
echo "x as ParameterizedType"
proc c[T](x: ParameterizedType[T]) =
echo "x as ParameterizedType[T]"
# remove the most specific one
proc d(x: ParameterizedType) =
echo "x as ParameterizedType"
proc d(x: CustomTypeClass) =
echo "x as CustomTypeClass"
# then shuffle the order again
proc e(x: CustomTypeClass) =
echo "x as CustomTypeClass"
proc e(x: ParameterizedType) =
echo "x as ParameterizedType"
# the least specific one is a match
proc f(x: CustomTypeClass) =
echo "x as CustomTypeClass"
a(ParameterizedType[int]())
b(ParameterizedType[int]())
c(ParameterizedType[int]())
d(ParameterizedType[int]())
e(ParameterizedType[int]())
f(ParameterizedType[int]())
block templates:
template typeLen(x): int = x.type.name.len
template bunchOfChecks(x) =
x.typeLen > 3
x != 10 is bool
template stmtListExprTmpl(x: untyped): untyped =
x is int
x
type
Obj = object
x: int
Gen[T] = object
x: T
Eq = concept x, y
(x == y) is bool
NotEq = concept x, y
(x != y) is bool
ConceptUsingTemplate1 = concept x
echo x
sizeof(x) is int
bunchOfChecks x
ConceptUsingTemplate2 = concept x
stmtListExprTmpl x
template ok(x) =
static: assert(x)
template no(x) =
static: assert(not(x))
ok int is Eq
ok int is NotEq
ok string is Eq
ok string is NotEq
ok Obj is Eq
ok Obj is NotEq
ok Gen[string] is Eq
ok Gen[int] is NotEq
no int is ConceptUsingTemplate1
ok float is ConceptUsingTemplate1
no string is ConceptUsingTemplate1
ok int is ConceptUsingTemplate2
no float is ConceptUsingTemplate2
no string is ConceptUsingTemplate2
block titerable:
type
Iterable[T] = concept x
for value in x:
type(value) is T
proc sum[T](iter: Iterable[T]): T =
static: echo T.name
for element in iter:
static: echo element.type.name
result += element
doAssert sum([1, 2, 3, 4, 5]) == 15
block tmanual:
template accept(e) =
static: assert compiles(e)
template reject(e) =
static: assert(not compiles(e))
type
Container[T] = concept c
c.len is Ordinal
items(c) is T
for value in c:
type(value) is T
proc takesIntContainer(c: Container[int]) =
for e in c: echo e
takesIntContainer(@[1, 2, 3])
reject takesIntContainer(@["x", "y"])
proc takesContainer(c: Container) =
for e in c: echo e
takesContainer(@[4, 5, 6])
takesContainer(@["a", "b"])
takesContainer "test"
reject takesContainer(10)
block modifiers_in_place:
type
VarContainer[T] = concept c
put(var c, T)
AltVarContainer[T] = concept var c
put(c, T)
NonVarContainer[T] = concept c
put(c, T)
GoodContainer = object
x: int
BadContainer = object
x: int
proc put(x: BadContainer, y: int) = discard
proc put(x: var GoodContainer, y: int) = discard
template ok(x) = assert(x)
template no(x) = assert(not(x))
static:
ok GoodContainer is VarContainer[int]
ok GoodContainer is AltVarContainer[int]
no BadContainer is VarContainer[int]
no BadContainer is AltVarContainer[int]
ok GoodContainer is NonVarContainer[int]
ok BadContainer is NonVarContainer[int]
block treversable:
type
Reversable[T] = concept a
a[int] is T
a.high is int
a.len is int
a.low is int
proc get[T](s: Reversable[T], n: int): T =
s[n]
proc hi[T](s: Reversable[T]): int =
s.high
proc lo[T](s: Reversable[T]): int =
s.low
iterator reverse[T](s: Reversable[T]): T =
assert hi(s) - lo(s) == len(s) - 1
for z in hi(s).countdown(lo(s)):
yield s.get(z)
for s in @["e", "z"].reverse:
echo s
block tmonoid:
type Monoid = concept x, y
x + y is type(x)
type(z(type(x))) is type(x)
proc z(x: typedesc[int]): int = 0
doAssert(int is Monoid)
# https://github.com/nim-lang/Nim/issues/8126
type AdditiveMonoid = concept x, y, type T
x + y is T
# some redundant checks to test an alternative approaches:
type TT = type(x)
x + y is type(x)
x + y is TT
doAssert(1 is AdditiveMonoid)
block tesqofconcept:
type
MyConcept = concept x
someProc(x)
SomeSeq = seq[MyConcept]
proc someProc(x:int) = echo x
proc work (s: SomeSeq) =
for item in s:
someProc item
var s = @[1, 2, 3]
work s
block tvectorspace:
type VectorSpace[K] = concept x, y
x + y is type(x)
zero(type(x)) is type(x)
-x is type(x)
x - y is type(x)
var k: K
k * x is type(x)
proc zero(T: typedesc): T = 0
static:
assert float is VectorSpace[float]
# assert float is VectorSpace[int]
# assert int is VectorSpace
block tstack:
template reject(e) =
static: assert(not compiles(e))
type
ArrayStack = object
data: seq[int]
proc push(s: var ArrayStack, item: int) =
s.data.add item
proc pop(s: var ArrayStack): int =
return s.data.pop()
type
Stack[T] = concept var s
s.push(T)
s.pop() is T
type ValueType = T
const ValueTypeName = T.name.toUpperAscii
proc genericAlgorithm[T](s: var Stack[T], y: T) =
static:
echo "INFERRED ", T.name
echo "VALUE TYPE ", s.ValueType.name
echo "VALUE TYPE NAME ", s.ValueTypeName
s.push(y)
echo s.pop
proc implicitGeneric(s: var Stack): auto =
static:
echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name
echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName
return s.pop()
var s = ArrayStack(data: @[])
s.push 10
s.genericAlgorithm 20
echo s.implicitGeneric
reject s.genericAlgorithm "x"
reject s.genericAlgorithm 1.0
reject "str".implicitGeneric
reject implicitGeneric(10)
import libs/[trie_database, trie]
block ttrie:
proc takeDb(d: TrieDatabase) = discard
var mdb: MemDB
takeDb(mdb)
import mvarconcept
block tvar:
# bug #2346, bug #2404
echo randomInt(5)

View file

@ -1,34 +0,0 @@
# bug #3452
import math
type
Node* = concept n
`==`(n, n) is bool
Graph1* = concept g
type N = Node
distance(g, N, N) is float
Graph2 = concept g
distance(g, Node, Node) is float
Graph3 = concept g
var x: Node
distance(g, x, x) is float
XY* = tuple[x, y: int]
MyGraph* = object
points: seq[XY]
static:
assert XY is Node
proc distance*( g: MyGraph, a, b: XY): float =
sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
static:
assert MyGraph is Graph1
assert MyGraph is Graph2
assert MyGraph is Graph3

View file

@ -1,13 +0,0 @@
# bug #6691
type
ConceptA = concept c
ConceptB = concept c
c.myProc(ConceptA)
Obj = object
proc myProc(obj: Obj, x: ConceptA) = discard
echo Obj is ConceptB

421
tests/concepts/tissues.nim Normal file
View file

@ -0,0 +1,421 @@
discard """
file: "tissues.nim"
output: '''
20.0 USD
Printable
true
true
true
true
true
f
0
10
10
5
()
false
true
true
true
true
p has been called.
p has been called.
implicit generic
generic
false
true
-1
Meow
'''
"""
import macros, typetraits
block t5983:
const currencies = ["USD", "EUR"] # in real code 120 currencies
type USD = distinct float # in real code 120 types generates using macro
type EUR = distinct float
type CurrencyAmount = concept c
type t = c.type
const name = c.type.name
name in currencies
proc `$`(x: CurrencyAmount): string =
$float(x) & " " & x.name
let amount = 20.USD
echo amount
block t3414:
type
View[T] = concept v
v.empty is bool
v.front is T
popFront v
proc find(view: View; target: View.T): View =
result = view
while not result.empty:
if view.front == target:
return
mixin popFront
popFront result
proc popFront[T](s: var seq[T]) = discard
proc empty[T](s: seq[T]): bool = false
var s1 = @[1, 2, 3]
let s2 = s1.find(10)
type
Obj1[T] = object
v: T
converter toObj1[T](t: T): Obj1[T] =
return Obj1[T](v: t)
block t976:
type
int1 = distinct int
int2 = distinct int
int1g = concept x
x is int1
int2g = concept x
x is int2
proc take[T: int1g](value: int1) =
when T is int2:
static: error("killed in take(int1)")
proc take[T: int2g](vale: int2) =
when T is int1:
static: error("killed in take(int2)")
var i1: int1 = 1.int1
var i2: int2 = 2.int2
take[int1](i1)
take[int2](i2)
template reject(e) =
static: assert(not compiles(e))
reject take[string](i2)
reject take[int1](i2)
# bug #6249
type
Obj2 = ref object
PrintAble = concept x
$x is string
proc `$`[T](nt: Obj1[T]): string =
when T is PrintAble: result = "Printable"
else: result = "Non Printable"
echo Obj2()
block t1128:
type
TFooContainer[T] = object
TContainer[T] = concept var c
foo(c, T)
proc foo[T](c: var TFooContainer[T], val: T) =
discard
proc bar(c: var TContainer) =
discard
var fooContainer: TFooContainer[int]
echo fooContainer is TFooContainer # true.
echo fooContainer is TFooContainer[int] # true.
fooContainer.bar()
block t5642:
type DataTable = concept x
x is object
for f in fields(x):
f is seq
type Students = object
id : seq[int]
name : seq[string]
age: seq[int]
proc nrow(dt: DataTable) : Natural =
var totalLen = 0
for f in fields(dt):
totalLen += f.len
return totalLen
let
stud = Students(id: @[1,2,3], name: @["Vas", "Pas", "NafNaf"], age: @[10,16,32])
doAssert nrow(stud) == 9
import t5888lib/ca, t5888lib/opt
block t5888:
type LocalCA = ca.CA
proc f(c: CA) =
echo "f"
echo c.x
var o = new(Opt)
echo o is CA
echo o is LocalCA
echo o is ca.CA
o.f()
import json
block t5968:
type
Enumerable[T] = concept e
for it in e:
it is T
proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
result = @[]
for it in e: result.add(fn(it))
var x = %["hello", "world"]
var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
assert z == @["hello!", "world!"]
import sugar
block t6462:
type
FilterMixin[T] = ref object
test: (T) -> bool
trans: (T) -> T
SeqGen[T] = ref object
fil: FilterMixin[T]
WithFilter[T] = concept a
a.fil is FilterMixin[T]
proc test[T](a: WithFilter[T]): (T) -> bool =
a.fil.test
var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
doAssert s.test() == nil
block t6770:
type GA = concept c
c.a is int
type A = object
a: int
type AA = object
case exists: bool
of true:
a: int
else:
discard
proc print(inp: GA) =
echo inp.a
let failing = AA(exists: true, a: 10)
let working = A(a:10)
print(working)
print(failing)
block t7952:
type
HasLen = concept iter
len(iter) is int
proc echoLen(x: HasLen) =
echo len(x)
echoLen([1, 2, 3, 4, 5])
block t8280:
type
Iterable[T] = concept x
for elem in x:
elem is T
proc max[A](iter: Iterable[A]): A =
discard
type
MyType = object
echo max(@[MyType()])
import math
block t3452:
type
Node = concept n
`==`(n, n) is bool
Graph1 = concept g
type N = Node
distance(g, N, N) is float
Graph2 = concept g
distance(g, Node, Node) is float
Graph3 = concept g
var x: Node
distance(g, x, x) is float
XY = tuple[x, y: int]
MyGraph = object
points: seq[XY]
static:
assert XY is Node
proc distance( g: MyGraph, a, b: XY): float =
sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
static:
assert MyGraph is Graph1
assert MyGraph is Graph2
assert MyGraph is Graph3
block t6691:
type
ConceptA = concept c
ConceptB = concept c
c.myProc(ConceptA)
Obj = object
proc myProc(obj: Obj, x: ConceptA) = discard
echo Obj is ConceptB
block misc_issues:
# https://github.com/nim-lang/Nim/issues/1147
type TTest = object
vals: seq[int]
proc add(self: var TTest, val: int) =
self.vals.add(val)
type CAddable = concept x
x[].add(int)
echo((ref TTest) is CAddable) # true
# https://github.com/nim-lang/Nim/issues/1570
type ConcretePointOfFloat = object
x, y: float
type ConcretePoint[Value] = object
x, y: Value
type AbstractPointOfFloat = concept p
p.x is float and p.y is float
let p1 = ConcretePointOfFloat(x: 0, y: 0)
let p2 = ConcretePoint[float](x: 0, y: 0)
echo p1 is AbstractPointOfFloat # true
echo p2 is AbstractPointOfFloat # true
echo p2.x is float and p2.y is float # true
# https://github.com/nim-lang/Nim/issues/2018
type ProtocolFollower = concept
true # not a particularly involved protocol
type ImplementorA = object
type ImplementorB = object
proc p[A: ProtocolFollower, B: ProtocolFollower](a: A, b: B) =
echo "p has been called."
p(ImplementorA(), ImplementorA())
p(ImplementorA(), ImplementorB())
# https://github.com/nim-lang/Nim/issues/2423
proc put[T](c: seq[T], x: T) = echo "generic"
proc put(c: seq) = echo "implicit generic"
type
Container[T] = concept c
put(c)
put(c, T)
proc c1(x: Container) = echo "implicit generic"
c1(@[1])
proc c2[T](x: Container[T]) = echo "generic"
c2(@[1])
# https://github.com/nim-lang/Nim/issues/2882
type
Paper = object
name: string
Bendable = concept x
bend(x is Bendable)
proc bend(p: Paper): Paper = Paper(name: "bent-" & p.name)
var paper = Paper(name: "red")
echo paper is Bendable
type
A = concept self
size(self) is int
B = object
proc size(self: B): int =
return -1
proc size(self: A): int =
return 0
let b = B()
echo b is A
echo b.size()
# https://github.com/nim-lang/Nim/issues/7125
type
Thing = concept x
x.hello is string
Cat = object
proc hello(d: Cat): string = "Meow"
proc sayHello(c: Thing) = echo(c.hello)
var a: Thing = Cat()
a.sayHello()

View file

@ -1,113 +0,0 @@
discard """
output: '''true
true
true
true
p has been called.
p has been called.
implicit generic
generic
false
true
-1
Meow'''
"""
# https://github.com/nim-lang/Nim/issues/1147
type TTest = object
vals: seq[int]
proc add*(self: var TTest, val: int) =
self.vals.add(val)
type CAddable = concept x
x[].add(int)
echo((ref TTest) is CAddable) # true
# https://github.com/nim-lang/Nim/issues/1570
type ConcretePointOfFloat = object
x, y: float
type ConcretePoint[Value] = object
x, y: Value
type AbstractPointOfFloat = concept p
p.x is float and p.y is float
let p1 = ConcretePointOfFloat(x: 0, y: 0)
let p2 = ConcretePoint[float](x: 0, y: 0)
echo p1 is AbstractPointOfFloat # true
echo p2 is AbstractPointOfFloat # true
echo p2.x is float and p2.y is float # true
# https://github.com/nim-lang/Nim/issues/2018
type ProtocolFollower = concept
true # not a particularly involved protocol
type ImplementorA = object
type ImplementorB = object
proc p[A: ProtocolFollower, B: ProtocolFollower](a: A, b: B) =
echo "p has been called."
p(ImplementorA(), ImplementorA())
p(ImplementorA(), ImplementorB())
# https://github.com/nim-lang/Nim/issues/2423
proc put*[T](c: seq[T], x: T) = echo "generic"
proc put*(c: seq) = echo "implicit generic"
type
Container[T] = concept c
put(c)
put(c, T)
proc c1(x: Container) = echo "implicit generic"
c1(@[1])
proc c2[T](x: Container[T]) = echo "generic"
c2(@[1])
# https://github.com/nim-lang/Nim/issues/2882
type
Paper = object
name: string
Bendable = concept x
bend(x is Bendable)
proc bend(p: Paper): Paper = Paper(name: "bent-" & p.name)
var paper = Paper(name: "red")
echo paper is Bendable
type
A = concept self
size(self) is int
B = object
proc size(self: B): int =
return -1
proc size(self: A): int =
return 0
let b = B()
echo b is A
echo b.size()
# https://github.com/nim-lang/Nim/issues/7125
type
Thing = concept x
x.hello is string
Cat = object
proc hello(d: Cat): string = "Meow"
proc sayHello(c: Thing) = echo(c.hello)
var a: Thing = Cat()
a.sayHello()