Nim: Why do we have type classes?

Created on 27 Oct 2018  路  7Comments  路  Source: nim-lang/Nim

Inspired by a newbie question: "What's the difference between proc tail[T](xs: seq[T]) and proc tail(xs: seq)?

Honestly the only reason for the second syntax to me seems to be: less typing. If that is the only reason then IMO it's grounds for this to be removed. We are already all using the more explicit syntax and offering this as an alternative is simply more overhead and more opportunity for breakage.

Thoughts?

Language design RFC

Most helpful comment

Maybe I'm misunderstanding, but you can write this:

Which is not the same thing. The issue is that Table and HashSet doesn't have the same number of type parameters.

import tables, sets
block:
  proc foo[T, U](x: Table[T, U] | HashSet[T]) = discard
  var s: HashSet[int]
  foo(s) # Error: cannot instantiate: 'U'
  foo[int, int](s) # Error: cannot instantiate: 'foo[int, int]'; got 2 type(s) but expected 3
  foo[int, int, Hashset[int]](s) # works
block:
  proc foo(x: Table | HashSet) = discard
  var s: HashSet[int]
  foo(s) # works

All 7 comments

I'm using the second syntax when T doesn't matter, for example when working only on metadata like len for sequences or shape or strides for tensors.

Type classes isn't just a syntax shortcut. There are things that can't be expressed with generics, e.g the type Table|HashSet (contrived example of course).

don't forget: less visual noise. I don't see any problems in supporting both.

There are things that can't be expressed with generics, e.g the type Table|HashSet (contrived example of course).

Maybe I'm misunderstanding, but you can write this:

proc foo[T, U](x: Table[T, U] | HashSet[T])

That also has the advantage that the intent is clearer.

don't forget: less visual noise. I don't see any problems in supporting both.

Less clarity as well. I prefer to be explicit rather than guess what the code is doing, and with these type classes I will need to do that. For example:

proc foo(x: seq, y: seq)

Is this proc foo[T](x: seq[T], y: seq[T]) or proc foo[T, U](x: seq[T], y: seq[U]? I can learn which one it is but it's not clear and many newbies will feel the same.

Maybe I'm misunderstanding, but you can write this:

Which is not the same thing. The issue is that Table and HashSet doesn't have the same number of type parameters.

import tables, sets
block:
  proc foo[T, U](x: Table[T, U] | HashSet[T]) = discard
  var s: HashSet[int]
  foo(s) # Error: cannot instantiate: 'U'
  foo[int, int](s) # Error: cannot instantiate: 'foo[int, int]'; got 2 type(s) but expected 3
  foo[int, int, Hashset[int]](s) # works
block:
  proc foo(x: Table | HashSet) = discard
  var s: HashSet[int]
  foo(s) # works

Is the question answered by now?

Well, I must admit I am disappointed because I still prefer the more explicit syntax and would prefer we solved this problem differently.

But oh well.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juancarlospaco picture juancarlospaco  路  3Comments

liquid600pgm picture liquid600pgm  路  3Comments

zzz125 picture zzz125  路  4Comments

Tronic picture Tronic  路  3Comments

alaviss picture alaviss  路  3Comments