bluenote10
bluenote10

Reputation: 26710

How to solve "no generic parameters allowed"

TL;DR: If you have a similar problem, check first that you haven't done something completely stupid like confusing a : with a =. I was so baffled by the error message that I managed to reproduce a stupid mistake by yet another stupid mistake, so have a good laugh:

I came upon a problem where I was struggling with the error no generic parameters allowed. The problem is probably best explained in a simplified from: The problem of comparing a tuple only by its first element. Consider this example:

import algorithm

# just a dummy type emphasizing that it should not be
# used for the comparison
type
  NotComparable = object

# generic proc to compare a tuple by the first element
proc cmpByKey[K,V](x: (K,V), y: (K,V)): int = 
  system.cmp(x[0], y[0])

# now the actual challenge: how to write a function which
# takes some collection of tuples and defines a local
# key comparator for the given tuple.
proc sortByFirstTupleElement[K,V](data: seq[(K,V)]) =
  let compare = cmpByKey[K,V]
  sort[(K,V)](cmp: compare)

let data = @[(2, NotComparable()),
             (1, NotComparable()),
             (3, NotComparable())]

sortByFirstTupleElement[int, NotComparable](data)

This example produces Error: no generic parameters allowed for sort. I have tried all kinds of syntactic variations, also defining the comparator proc nested. What I do not understand: Why is the comparator still considered generic? I was expecting that within sortByFirstTupleElement the types K and V are instantiated types from the calling context, i.e, int and NotComparable. Therefore I expected cmpByKey[K,V] to be the concrete cmpByKey[int,NotComparable]. Is there a syntactic trick to make the comparator concrete?

If this is not possible, what are the possible workarounds here? Maybe not just specifically in this example, but in general? I guess this problem arises every time a generic proc has to pass on another proc which involves the generic type?

Upvotes: 1

Views: 601

Answers (1)

Reimer Behrends
Reimer Behrends

Reputation: 8730

Your problem is that you're calling sort with the wrong parameters. You don't pass the data parameter to sort, and data is not a var parameter, so it isn't mutable. Also, cmp is not a named parameter, so just pass the comparison function directly. E.g.:

import algorithm

# just a dummy type emphasizing that it should not be
# used for the comparison
type
  NotComparable = object

# generic proc to compare a tuple by the first element
proc cmpByKey[K,V](x: (K,V), y: (K,V)): int = 
  system.cmp(x[0], y[0])

# now the actual challenge: how to write a function which
# takes some collection of tuples and defines a local
# key comparator for the given tuple.
proc sortByFirstTupleElement[K,V](data: var seq[(K,V)]) =
  let compare = cmpByKey[K,V]
  data.sort(compare)

var data = @[(2, NotComparable()),
             (1, NotComparable()),
             (3, NotComparable())]

sortByFirstTupleElement(data)

Also, the let compare = ... is superfluous. You can call data.sort(cmpByKey[K,V]) directly.

You get the error message because you're using the object constructor syntax (cmp: compare) rather than the named parameter syntax (cmp = compare), which makes Nim look for an object type called sort rather than a procedure called sort. The error message is still a bit confusing, but that's where it's coming from.

Upvotes: 4

Related Questions