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. :-) )
