Description
Example
sample of 8 bugs with new style concepts:
when defined case1:
#[
BUG:D20210609T174202:here doesn't honor func
]#
type Foo = concept
func bar(x: Self): Self
proc bar(a: int): int = (echo "asdf"; 1)
doAssert int isnot Foo # assert fails, but should succeed because bar has sideeffects
when defined case2:
#[
BUG:D20210609T174206:here doesn't work with auto
]#
type Foo = concept
proc bar(x: Self): Self
proc bar(a: int | float): auto = a
doAssert int is Foo # fails
when defined case3:
#[
BUG: D20210609T175144:here doesn't work with overloaded symbols
]#
type Foo = concept
proc bar(x: Self): int
proc bar(a: int | float): int = 1
proc bar(a: string): int = 1
doAssert string is Foo # fails
when defined case4:
#[
BUG: D20210609T180457:here doesn't generic constraints
]#
type Foo = concept
proc bar[T: SomeInteger](x: Self, b: T): T
proc bar[T: SomeInteger](x: string, b: T): T = discard
doAssert string is Foo # fails
when defined case5:
#[
BUG:D20210609T182307:here doesn't work with var
]#
type Foo = concept
proc bar(a: seq[Self])
proc bar(a: var seq[string]) = discard
echo string is Foo # prints true, should print false
proc fn(a: Foo) = bar(@[a])
echo compiles(fn("x")) # prints false as expected because '@[a]' is immutable, not 'var'
when defined case6:
#[
BUG: D20210609T183337:here doesn't work with static params
]#
type Foo = concept
proc bar(a: Self, b: static int) = discard
proc bar(a: string, b: static int) = discard
doAssert string is Foo # fails
when defined case7:
#[
BUG: D20210609T183337:here doesn't work with static params
]#
type Foo = concept
proc bar(a: Self, b: typedesc) = discard
proc bar(a: string, b: typedesc) = discard
doAssert string is Foo # fails
when defined case8:
#[
BUG: D20210609T190543:here doesn't work with called iterators (iterables)
]#
type Summable = concept
template sum(a: iterable[Self]): int = discard # doesn't help
# proc sum(a: iterable[Self]): int # doesn't help
iterator iota(n: int): int = (for i in 0..<n: yield i)
template sum[T](a: iterable[T]): T =
var ret: T
for ai in a: ret += ai
ret
doAssert sum(iota(3)) == 0 + 1 + 2
template sum2(a: Summable): untyped = sum(a) * 2
echo sum2(iota(3)) # Error: attempting to call routine: 'iota'
not to mention all the other concept issues already reported: Concepts (currently 42 open issues)
Current Output
all those cases fail
Expected Output
those cases should pass
Possible Solution
{.enableif.}
, which I implemented in #12048 (which i will rename as {.where.}
) , was wrongly closed.
It doesn't have any of the problems of concepts (whether old style or new style), is more flexible and is a much simpler solution leveraging the compiler's existing expression evaluator; it's also the solution adopted by these:
- D (template constraints, refs https://dlang.org/concepts.html)
- C++ (enableif); C++ concepts only exist because enableif syntax in C++ sucks
- clang attribute (
__attribute__((enable_if ...))
- rust (
where
), refs https://doc.rust-lang.org/std/keyword.where.html, see corresponding RFC that was written at the time when it was introduced: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md and PR: Where clauses for more expressive bounds rust-lang/rfcs#135 - C# (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint)
- swift:
where
, https://docs.swift.org/swift-book/LanguageGuide/Generics.html#:~:text=%7D-,Generic%20Where%20Clauses,defining%20a%20generic%20where%20clause. - haskell: where (https://stackoverflow.com/questions/10434333/how-do-i-give-expressions-generic-types-in-a-where-clause)
etc
In short, enableif is the obvious, simpler, more flexible approach and we should use it.
Note that we could even define concepts on top of enableif (enableif subsumes concepts):
type Foo = concept x {.enableif: bar(x) is int.}
on top of {.enableif.}
, to allow the same syntax where needed, eg:
type Foo = concept x {.enableif: bar(x) is int.}
proc fn(a: Foo)
proc fn(a: auto) {.enableif: bar(a) is int.}
proc fn[T](a, b: auto, c: int, d: T) {.enableif: bar(a, b, T).} # not possible with concepts
Additional Information
1.5.1 21f3b85