Hi,
I'm taking a look into concept[T]. I hope you don't mind, I'll probably ask for some help on this forum from time to time.
Could you please take a very careful look at the following code? This is not working (right now), but should it work with this syntax?
# Container must have a "get" function
type Container[T] = concept c
get(c, 0) is T # THIS IS UPDATED, previous wrong syntax was: get(c, int) is T
# We create this "get" function for seq[T],
# therefore seq[int] is a Container
proc get[T](c: seq[T], i: int): T = c[i]
# Any container can have the first element:
proc first[T](x: Container[T]): T = get(x, 0)
# Use "first" on a seq[int]
echo first(@[10,11,12])
By the way, is myVar is myType equivalent to type(myVar) == myType? If yes, then is type(value) is T in the manual's "Concepts" section a typo?
type Container[T] = concept c
get(c, int) is T
No, int is a typedesc[int] which is not at all what get gets, use an int instead (get(c, 0) is T). (The manual needs to be updated.)
By the way, is myVar is myType equivalent to type(myVar) == myType? If yes, then is type(value) is T in the manual's "Concepts" section a typo?
Since there is no equality for typedescs, type(myVar) == myType is not valid and not the same as the is operator.
@Araq it still doesn't compile:
Error: type mismatch: got (seq[int]) but expected one of: proc firstT: T
Mainly, because of "Generic concepts" (Foo[T] = concept) don't work." . Also, it's pretty weird to describe type signatures with values, isn't it?
concept is likely the most misunderstood language feature
This is true because (almost?) everybody wants it to be something like a typeclass or an interface but it's none of these. And the temporary solution - the tuple-of-procs - isn't so convenient and can't describe relations between such tuples. So, I'm really interested in what it'll turn out to be.
Thanks for the feedback (corrected get(c,0) and yes, no equality for typedescs).
This doesn't look like an easy task (summary: concepts are not working, the documentation is outdated, and it is likely the most misunderstood language feature). Currently I'm working on a tool which will make the debugging easier.
By the way, a couple of quick questions. If get(c,int) is not valid, then is there a way to ask for a variable with the given type and with the default value inline? This is the best I have: get(c, newSeq[int](1)[0]) (in this form you can replace int with T).
My other question: should the following code work? (However, it is not a good practice)
type Container[T] = concept c
get(c, 0) is T
# We create this "get" function for seq[T],
# therefore seq[int] is a Container
proc get[T](c: seq[T], i: int): T = c[i]
# Sum the elements
proc sum[T](x: Container[T]): T =
for i in 0..<x.len:
result += get(i, 0)
# Use "sum" on a seq[int]
echo sum(@[10,11,12])
Here nobody guarantees that x.len is implemented and T+T is valid (and + would fail for seq[string]). However, it should work, right? This feels like python's duck typing, and Rust wouldn't allow this (there you need to specify everything which you want to do with the template).This doesn't look like an easy task ...
Maybe we can just steal Rust's trait system instead.
My other question: should the following code work?
Yes for the current spec. In the longer run it would be nice to make it sound. (No duck typing for concept.)
@mora
is there a way to ask for a variable with the given type and with the default value inline?
Not inline, but you can do
var x: T
get(c, x)
where T is your type
It does not work what @mora wrote.
Even with corrected code. See:
proc sum[T](x: Container[T]): T =
for i in 0..<x.len:
result += get(i, 0)
should be
proc sum[T](x: Container[T]): T =
for i in 0..<x.len:
result += get(x, i)
though.
Oh, yes, I was not able to put together a small example. Just wait until I touch the compiler's code, and see what I'll break :)
@andrea: I'm not sure that you can create variables in a concept, that's why I wanted to have it inline. Let me give an example where it is needed:
type Map[T,S] = concept c
get(c, default(T)) is S
hasKey(c, default(T)) is bool
values(c) is seq[S]
# ...
where default(T) is some inline expression which gives a variable with the given type (e.g., new(T)[]). And sorry, I haven't tried out your Emmy library, but I'll.
Peter
Maybe we can just steal Rust's trait system instead.
That's fine in theory. But Rust builds very slowly. I am no expert on compilers. What I know is that 2 of Go's greatest strengths are simplicity and fast compilation. I would recommend whatever language features are easiest to implement and quickest to parse.
@mora You can definitely create variables in a concept. Actually, you can write pretty much what you want in the body of a concept, and the concept will be assigned to a type if substituting for that type makes the body compile. After that, there is no codegen phase, hence you are not actually creating a variable - i.e. allocating space - it's only there for the purpose of checking whether something compiles.
About Emmy: it is a little stuck right now, due to a bug in handling static[T], which prevents me to write an efficient implementation of modular arithmetic