Hi,
I'd like to create a Nim concept with an "associated type", i.e. a type known to the concept, but not the concept's own "type". Something like:
type NumTest* = concept x, y
type Epsilon
is_eq(x, y, Epsilon) is bool
is_ne(x, y, Epsilon) is bool
Then later, I could provide implementations for float, with both float and int epsilon types:
func is_eq(x, y, epsilon: float) = ...
func is_eq(x, y: float, epsilon: int) = ...
Which seems to cause type mismatches in practice. I'm not sure I'm going about this in an idiomatic Nim style. I also considered a generic concept over the Epsilon type, which doesn't seem right either.
Any advice much appreciated.
Stu
You want the existential type ( = type exists ). The concept should find out an underlying type that is part of the concept, the type being abstract (not revealed to the outside) but being used within the functions.
I tried several things to achieve such a behaviour but it is not possible. Concepts can't pattern match on procs, therefore they can't assign a parametric type to a function parameter.
You can do something like this, although I'm not sure it's what you want:
type NumTest[T] = concept x, y
is_eq(x, y, T) is bool
is_ne(x, y, T) is bool
proc is_eq(x, y, epsilon: float): bool =
x == y
proc is_eq(x, y: float, epsilon: int): bool =
x == y
proc is_ne(x, y, epsilon: float): bool =
x != y
proc is_ne(x, y: float, epsilon: int): bool =
x != y
proc doEp(x, y: NumTest) =
echo x.is_eq(y, 1)
echo x.is_ne(y, 1)
echo x.is_eq(y, 1.3)
echo x.is_ne(y, 1.5)
proc main() =
doEp(12.3, 13.4)
doEp(12.3, 12.3)
main()
Thanks for that -- I did try that approach and wondered if there was some aspect of concepts that I was misunderstanding or not seeing.
Ta,
Stu
Thanks -- some food for thought there.
Stu
this won't compile if is_eq/is_ne are generic over Epsilon, but it seems to me to be how to associate a type with a concept. @stu002, what 'seemed wrong' about this approach/what's your actual goal?
I'm coming at this as a relative newbie to Nim so it seemed like there was some capability of the way concept elements are checked for truth that I was missing. After feedback it looks like the most idiomatic way to do this in Nim is with the generic concept parameter.
My goal is just to go with the language and not against it where I can. Many thanks to everyone who replied to this thread and the discussion on Discourse.
After feedback it looks like the most idiomatic way to do this in Nim is with the generic concept parameter.
You asked for a type "that is not known to the concept". But with the generic concept parameter, the type becomes part of the concept because it belongs to its instantiation type, e.g. NumTest[float] .
this won't compile if is_eq/is_ne are generic over Epsilon
It compiles anyway:
type NumTest[T] = concept x, y
is_eq(x, y, T) is bool
is_ne(x, y, T) is bool
proc is_ne[T](x, y, epsilon: T): bool =
echo "generic ne T ", T.type
x != y
proc is_eq(x, y, epsilon: float): bool =
x == y
proc is_eq(x, y: float, epsilon: int): bool =
echo "specified eq ", epsilon.type
x == y
proc is_ne(x, y, epsilon: float): bool =
echo "specified eq ", epsilon.type
x != y
proc is_ne(x, y: float, epsilon: int): bool =
echo "specified ne ", epsilon.type
x != y
proc doEp(x, y: NumTest) =
discard x.is_eq(y, 1)
discard x.is_ne(y, 1)
discard x.is_eq(y, 1.3)
discard x.is_ne(y, 1.5)
proc run() =
doEp(12.3, 13.4)
doEp(12.3, 12.3)
run()
#type NumTest[T] = concept x, y
is_eq(x, y, T) is bool
is_ne(x, y, T) is bool
proc is_ne[T](x, y, epsilon: T): bool =
echo "generic ne T ", T.type
x != y
proc is_eq(x, y, epsilon: float): bool =
x == y
proc is_eq(x, y: float, epsilon: int): bool =
echo "specified eq ", epsilon.type
x == y
proc is_ne(x, y, epsilon: float): bool =
echo "specified eq ", epsilon.type
x != y
proc is_ne(x, y: float, epsilon: int): bool =
echo "specified ne ", epsilon.type
x != y
proc doEp(x, y: NumTest) =
discard x.is_eq(y, 1)
discard x.is_ne(y, 1)
discard x.is_eq(y, 1.3)
discard x.is_ne(y, 1.5)
proc run() =
doEp(12.3, 13.4)
doEp(12.3, 12.3)
run()
I implemented both a generic and specific function for is_ne . I modified the code slightly to reveal the instantiation.
Generic (pattern matching) use of a type parameter within concept x,type U
The mentioned concept NumTest would compile as :
type NumTest[T] = concept x,y, type U
is_eq(x, float , T) is bool
is_ne(x, y, T) is bool
so the type of x is float and therefore type U has type float as well. But if we modify the concept accordingly
type NumTest[T] = concept x, type U
is_eq(x, U , T) is bool
is_ne(float, y , T) is bool
(an U for a float) it would not compile anymore.where i got stuck was here:
import strformat
type NumTest[T] = concept x, y
is_eq(x, y, T) is bool
is_ne(x, y, T) is bool
proc is_ne[T](x, y, epsilon: T): bool =
echo &"generic ne {$x.type} {$epsilon.type}"
x != y
proc is_eq[T](x, y, epsilon: T): bool =
echo &"generic eq {$x.type} {$epsilon.type}"
x == y
proc doEp(x, y: NumTest) =
discard x.is_eq(y, 1)
discard x.is_ne(y, 1)
discard x.is_eq(y, 1.3)
discard x.is_ne(y, 1.5)
proc run() =
doEp(12.3, 13.4)
doEp(12.3, 12.3)
doEp(12,13)
run()
results in a type mismatch, as does
proc is_ne[S,T](x, y: S; epsilon: T): bool =
echo &"generic eq {$x.type} {$epsilon.type}"
x != y
proc is_eq[S,T](x, y: S; epsilon: T): bool =
echo &"generic eq {$x.type} {$epsilon.type}"
x == y
Many thanks to everyone who replied to the discussion on Discourse.
Discourse ?, or Nim forum ?.
https://play.nim-lang.org/#ix=3rrU
the change i made was removing the non-generic overloads and adding doEp(12,13) i removed the specializations from your original version as the generic was never getting called.
I'm not surprised that the first one doesn't compile, as i'm trying to call <int, int, float>
Which is why I tried the is_ne[S,T] version, which also doesn't compile, not on 1.4.6, not on devel, not with new-style concepts either.
the change i made was removing the non-generic overloads and adding doEp(12,13) i removed the specializations from your original version as the generic was never getting called.
I didn't remove them. Anyway, how to express in the concept, that T is distinct from the types for x and y ?