https://github.com/sls1005/closureconcepts
Concepts are generic constraints, they are not interfaces and not traits, they have nothing to do with dynamic binding.
You may already know it, below Github search string will find all the nim code using concept
"= concept" language:Nim path:/
Owlkettle (a GTK wrapper) makes minor use of them in order to provide a better generic solution for an "automatic-form-generator".
Other than that, a lib that makes heavier use of it would be traitor: https://github.com/beef331/traitor/blob/master/traitor.nim
Made by ElegantBeef -Who is definitely not standing behind me with a gun to the back of my head
Emmy has a big use of concepts: https://github.com/andreaferretti/emmy
type
AdditiveMonoid* = concept x, y, type T
x + y is T
zero(T) is T
AdditiveGroup* = concept x, y, type T
T is AdditiveMonoid
-x is T
x - y is T
MultiplicativeMonoid* = concept x, y, type T
x * y is T
id(T) is T
MultiplicativeGroup* = concept x, y, type T
T is MultiplicativeMonoid
x / y is T
Ring* = concept type T
T is AdditiveGroup
T is MultiplicativeMonoid
EuclideanRing* = concept x, y, type T
T is Ring
x div y is T
x mod y is T
Field* = concept type T
T is Ring
T is MultiplicativeGroup
And besides Arraymancer, I use this simple Hash function concept to build further cryptography on top of hash functions: https://github.com/mratsim/constantine/blob/58d8d2c/constantine/hashes.nim#L17-L38
type
CryptoHash* = concept h, var ctx, type H
## Interface of a cryptographic hash function
##
## - digestSizeInBytes is the hash output size in bytes
## - internalBlockSize, in bits:
## hash functions are supposed to ingest fixed block size
## that are padded if necessary
## - SHA256 block size is 64 bits
## - SHA512 block size is 128 bits
## - SHA3-512 block size is 72 bits
# should we avoid int to avoid exception? But they are compile-time
H.digestSize is static int
H.internalBlockSize is static int
# Context
# -------------------------------------------
ctx.init()
ctx.update(openarray[byte])
ctx.finish(var array[H.digestSize, byte])
ctx.clear()
And with all those primitives, I can create a generic hash
func hash*[DigestSize: static int](
HashKind: type CryptoHash,
digest: var array[DigestSize, byte],
message: openArray[byte],
clearMem = false) {.genCharAPI.} =
## Produce a digest from a message
static: doAssert DigestSize == HashKind.type.digestSize
var ctx {.noInit.}: HashKind
ctx.init()
ctx.update(message)
ctx.finish(digest)
if clearMem:
ctx.clear()
func hash*(
HashKind: type CryptoHash,
message: openArray[byte],
clearmem = false): array[HashKind.digestSize, byte] {.noInit, genCharAPI.} =
## Produce a digest from a message
HashKind.hash(result, message, clearMem)
And then I can do sha256.hash(message)