Nim icon indicating copy to clipboard operation
Nim copied to clipboard

[Concept] predicate checking for proc return types `seq[X]` fail for `type X` concept parameter

Open PhilippMDoerner opened this issue 2 years ago • 2 comments

Description

I wanted a concept that checks if there are several procs defined for the given type. One of those procs returned a seq of that type, so I wanted to check for that. When you do so and use a type <TypeAliasName> concept parameter, the predicate that checks for the proc will always fail.

Minimal Example:

type ExampleConcept = concept example, type Typ
  list() is seq[Typ] # This always fails

type Example = object
proc list(): seq[Example] = @[Example()]

proc foo(x: ExampleConcept) = echo "bar"

let ex = Example()
ex.foo()

Nim Version

Nim Compiler Version 2.0.0 [Linux: amd64] Compiled at 2023-08-01 Copyright (c) 2006-2023 by Andreas Rumpf

git hash: a488067a4130f029000be4550a0fb1b39e0e9e7c active boot switches: -d:release

Current Output

Error: type mismatch
Expression: foo(ex)
  [1] ex: Example

Expected one of (first mismatch at [position]):
[1] proc foo(x: ExampleConcept)
/home/philipp/dev/playground/src/playground.nim(4, 3) ExampleConcept: concept predicate failed

Expected Output

bar

Possible Solution

As a workaround you can infer the type from a concept's instance variable instead, which somehow works :

type ExampleConcept = concept example, type Typ
  list() is seq[example.type]

type Example = object
proc list(): seq[Example] = @[Example()]

proc foo(x: ExampleConcept) = echo "bar"

let ex = Example()
ex.foo()

Therefore fundamentally the feature works, it just doesn't interpret seq[Typ] correctly for some reason.

Additional Information

I had assumed this may affect any generic type such as e.g. Table or Set, but when I tested this for Table it worked perfectly fine.

import std/tables
type ExampleConcept = concept example, type Typ
  list() is Table[string, Typ]

type Example = object
proc list(): Table[string, Example] = discard

proc foo(x: ExampleConcept) = echo "bar"

let ex = Example()
ex.foo()

So I'm not sure why seqs are specifically singled out with this problem.

Note: I've seen a ton of other concept issues, some fairly similar to this, but all of them seemed a bit more "complex". This here seems to be a less "complex" scenario where the problem occurred, so I thought it might be a separate issue.

PhilippMDoerner avatar Oct 28 '23 11:10 PhilippMDoerner

wow just encountered this

type
  TreeNodeRec* = ref object ## used in frontend
    # children*: TreeNodeRec ## works with single
    children*: seq[TreeNodeRec] # XXX does not work with seq

  Node = concept t, type T   
    # t.children is typeof t ## works with single
    # t.children is T ## works with single

    t.children is seq[typeof t] # works with seq
    # t.children is seq[T] # XXX does not work with seq


func match*(n: Node): int = 1

when isMainModule:
  echo match TreeNodeRec()

hamidb80 avatar Mar 26 '24 20:03 hamidb80

new discovery. this works:

type
  TreeNodeRec* = ref object
    children*: seq[TreeNodeRec]

  # Node = concept t, type T #
  Node = concept t
    type T = typeof t
    t.children is seq[T]


func match*(n: Node): int = 1

echo match TreeNodeRec()

hamidb80 avatar Mar 29 '24 13:03 hamidb80