I can think of an example where the concept = container logic fails. Let's
assume that we have `Set[T]` concept, and one would like to implement it for
`T=char` by using a bitfield (that's 4 times 64-bit `int`, so it is an
`array[4, int]`). This could be `Set[char]`, however, there is no `char` in
this type's syntax.
Also, Andrea, you are right. You would like to have several `concept` types
with a small difference, where the difference is in one of the types. And that
is what generics is for.
Repeating the obvious, these are the two cases we would like to have:
proc giveFirstValue[K,V](m : Map[K,V]): V = ... # here Map[K,V] defines K, V
proc RandomLinearCombination(x, y: VectorSpace[float]): auto = ... # here
VectorSpace[T] needs to know T
How about having both of these? We could introduce the generic symbols within
the concept, they would be the given types, or if no type is available, then
the default value would be a type which doesn't match to anything. And they
would be mutable.
For example
type ThisRequiresType[T] = concept c
c[0][0].foo[0] is T
c + c is int
This would match a parameter only if `T` is given (or can be find out from a
previous generic match, like `proc[S] f(a: S, b: ThisRequiresType[S])`). If `T`
is not given, then it would fail at every `something is T` check.
The other example:
type ContainerWithAddableElements[T] = concept c
T = type(c[0])
c[0] + c[0] is T
Here the first line would overwrite `T`, so it could be used in function
definitions like `proc first[S](x: ContainerWithAddableElements[S]): S = c[0]`.
So again, the steps would be: we introduce symbols for every generics at the
beginning of the concept, they are mutable, and their values are the given
ones, or if we cannot infer them, then they would be a type which matches
nothing. The evaluation needs to be successful to continue, and then we check
the values of these type symbols, and match them with any generics if we are in
a function declaration.
What do you think?
> Peter