In [my 
code](https://hg.sr.ht/~sschwarzer/todoreport/browse/default/src/todoreport/task.nim)
 I have a proc that returns a `cmp` proc for sorting with `algorithm.sorted`:
    
    
    type
      Task* = object
        isComplete*: string
        priority*: string
        # We could model the dates as `times.DateTime`, however the strings are
        # fine for our purpose since we can sort them as strings due to the
        # ISO 8601 format.
        completionDate*: string
        creationDate*: string
        # Does include "+" prefixes
        projects*: HashSet[string]
        # Does include "@" prefixes
        contexts*: HashSet[string]
        # TODO: Add support for tags (key:value pairs)
        # Original complete line
        line*: string
        # Everything after the "fixed-format" fields "x (A) 2020-01-05 
2020-01-03"
        description*: string
    
    proc cmpTaskField*(fieldName: string): proc (task1, task2: Task): int =
      case fieldName
      of "isComplete":
        return proc (task1, task2: Task): int =
          cmp(task1.isComplete, task2.isComplete)
      of "priority":
        return proc (task1, task2: Task): int =
          cmp(task1.priority, task2.priority)
      of "completionDate":
        return proc (task1, task2: Task): int =
          cmp(task1.completionDate, task2.completionDate)
      of "creationDate":
        return proc (task1, task2: Task): int =
          cmp(task1.creationDate, task2.creationDate)
      of "line":
        return proc (task1, task2: Task): int =
          cmp(task1.line, task2.line)
      of "description":
        return proc (task1, task2: Task): int =
          cmp(task1.description, task2.description)
    
    
    Run

`cmpTaskField` 
[works](https://hg.sr.ht/~sschwarzer/todoreport/browse/default/src/todoreport.nim)
 (the last few statements are the relevant ones): 
    
    
    proc sortedTasks(tasks: seq[Task]; keysString = ""): seq[Task] =
      ## Sort `tasks` in-place according to the spec in `keysString`. For 
example,
      ## if `keysString` is "prio,crd", sort tasks first by priority, then by
      ## creation date.
      if not keysStringIsAllowed(keysString, "x,prio,crd,cod,line,desc"):
        raise newException(KeyError, &"invalid keys string \"{keysString}\"")
      # According to the `algorithms` documentation, `sort` is stable, so we can
      # sort first for the least significant key and last for the most 
significant
      # key.
      var tasks = tasks
      let keyStrings = splitKeysString(keysString).reversed()
      for keyString in keyStrings:
        var
          keyString = keyString
          sortOrder = SortOrder.Ascending
        if keyString.endsWith("-"):
          sortOrder = SortOrder.Descending
          keyString = strip(keyString, trailing = true, chars = {'-'})
        let
          fieldName = groupAndSortKeys[keyString]
          cmpFunc = cmpTaskField(fieldName)
        tasks = sorted(tasks, cmpFunc, order = sortOrder)
      tasks
    
    
    Run

Now, obviously `cmpTaskField` has a lot of redundancy, so I'm trying to use a 
template: 
    
    
    template cmpTaskField*(fieldName: untyped): untyped =
      proc cmp(task1, task2: Task): int = cmp(task1.fieldName, task2.fieldName)
    
    var tasks = @[Task(isComplete: "b"), Task(isComplete: "a")]
    tasks = sorted(tasks, cmp = cmpTaskField(isComplete))
    #tasks = sorted(tasks, cmp = proc (task1, task2: Task): int = 
cmp(task1.isComplete, task2.isComplete))
    
    echo tasks
    
    
    Run

(see also 
[https://play.nim-lang.org/#ix=26CR](https://play.nim-lang.org/#ix=26CR) for an 
- almost ;-) - runnable example)

However, I get the compiler message: 
    
    
    Hint: used config file '/playground/nim/config/nim.cfg' [Conf]
    Hint: system [Processing]
    Hint: widestrs [Processing]
    Hint: io [Processing]
    Hint: in [Processing]
    Hint: algorithm [Processing]
    /usercode/in.nim(25, 15) Error: type mismatch: got <seq[Task], cmp: void>
    but expected one of:
    proc sorted[T](a: openArray[T]; cmp: proc (x, y: T): int {.closure.};
                  order = SortOrder.Ascending): seq[T]
      first type mismatch at position: 2
      required type for cmp: proc (x: T, y: T): int{.closure.}
      but expression 'cmp = proc cmp(task1`gensym135043, task2`gensym135044: 
Task): int =
      result = cmp(task1`gensym135043.isComplete, task2`gensym135044.isComplete)
    ' is of type: void
    proc sorted[T](a: openArray[T]; order = SortOrder.Ascending): seq[T]
      first type mismatch at position: 2
      unknown named parameter: cmp
    
    expression: sorted(tasks, cmp = proc cmp(task1`gensym135043, 
task2`gensym135044: Task): int =
      result = cmp(task1`gensym135043.isComplete, task2`gensym135044.isComplete)
    
    )
    
    
    Run

It seems to me that somehow the proc "returned" from the template isn't visible 
at the place where it's used. As far as I understand the 
[manual](https://nim-lang.org/docs/manual.html#templates-hygiene-in-templates), 
the proc should be visible. (And adding `{.inject.}` to the proc doesn't change 
anything, so at least that's consistent. ;-)

What's missing? How should the code be changed and why?

(For the record, I read the section on templates in the Nim manual, but I 
understood at most half of it, so please be forgiving. :-) )

Reply via email to