Skip to content

bugs with new-style concepts #18225

Open
Open
@timotheecour

Description

@timotheecour

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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions