I appreciate the concept proposal to move into the direction of type classes.
However, there are two things which I find a bit annoying:
1.) Given the example:
type
Comparable = concept x, y
(x %<% y) is bool
proc `%<%`(c1:int,c2:int):bool=c1<c2
proc `%<%`(c1:float,c2:float):bool=c1<c2
#1
proc fun(c1:var Comparable,c2: var Comparable)=...
#2
proc fun[S:Comparable](c1:var S,c2: var S)=...
#3
proc fun[S,T:Comparable](c1:var S,c2: var T)=...
var i:int=1
var j:float=2.0
echo fun(i,j)
most people would naturally think of #1 being equal to #3, but it is actually equal to #2.
2.) Moreover, writing fun(s:Concept) instead of fun[S:Concept](s:S) making it easier to forget that the function is still generic. I could imagine that library maintainers will massively incorporate concepts into their frameworks and exchange data to other frameworks only over concepts as they are very flexible. This would lead to massive code generation because of the specified behavior:
Much like generics, concepts are instantiated exactly once for each tested type and any static code included within the body is executed only once.
Imagine calling public procs calling many private procs will duplicate big parts of your framework for each conforming type passed in.
My advice would be to treat fun(c:Concept) as a boxed function with only one function body generated for all conforming types. While fun[T:Concept](c:T) would do what is expected. Moreover, allowing different conforming types for a function signature requires anyways to use generic type parameters.
Another point would be to allow the user to specify box/unbox behavior as pragma for each function taking a concept, but without solving point 1.) it still feels unnatural and solving 1.) would allow to exchange the conforming type in the function body which can't always be unboxed then.
Are you aware of that concepts redesign was merged recently?
Thanks, interesting to see we are moving forward.
However, listed under the "More Examples" section:
We still have code like this:
proc find(x: Findable[T]; elem: T): int =
var i = 0
for a in x:
if a == elem: return i
inc i
return -1
So what 's the difference to the older proposal?
My advice would be to treat fun(c:Concept) as a boxed function with only one function body generated for all conforming types. While funT:Concept would do what is expected.
I like this idea and I think Swift's generics also work this way. It's very much work to implement, so don't hold your breath. However, you can help us by writing a proposal to fathom this design.