mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 18:02:05 +00:00
* fixes #15210 [backport:1.2] * make tests green * make ordinal work * makes Swapable test compile * make Indexable example work * concepts: 'self' is now 'Self' * concepts: make Dictionary example compile * document the new concept implementation * concepts: make typeDesc work properly * concepts: allow documentation comments (d'oh)
441 lines
7.8 KiB
Nim
441 lines
7.8 KiB
Nim
discard """
|
|
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 c
|
|
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)
|