Nim: non ordinal enums are not allowed in set constructor

Created on 24 Jul 2018  路  8Comments  路  Source: nim-lang/Nim

type
  AuthenticationMethod* = enum
    NO_AUTHENTICATION_REQUIRED = 0x00.byte
    GSSAPI = 0x01.byte
    USERNAME_PASSWORD = 0x02.byte
    NO_ACCEPTABLE_METHODS = 0xFF.byte

proc `in`*(bytesMethod: seq[byte], authMethods: set[AuthenticationMethod]): bool =
  for byteMethod in bytesMethod:
    if byteMethod.AuthenticationMethod in authMethods: return true
  return false

#fails with Error: ordinal type expected
Regression Showstopper

Most helpful comment

For the time being, set should continue to accept enums with holes. Working on it.

All 8 comments

A set is a packed bitfield that uses the enum values as index.

I.e. your set would use bit 0, bit 1, bit 2 and bit 255. But this is not packed anymore since bit: 3..254 are unused.

This would prevent iterating over the set as items rely on the packed dense representation.

In conclusion i think this is not a bug, and it would be a heavy feature to implement see #7699 #8132 #8264 .

As a workaround:

  • Fill the holes, see this macro.
  • Or use a HashSet.

@mratsim I don't think that using non ordinal types in sets should be a problem. Most sets operations work just fine. In order to iterate, you can just iterate over the set as if it was packed (e.g a set if uint8) and then filter only these integer values that correspond to valid enum values. Alternatively, items could have the signature

iterator items[T: Ordinal](s: set[T])

Other valid uses of sets (e.g. as option masks) do not need a contiguous enum

i think this is a regression, this is part of old (once working) code

@enthus1ast Enums with holes have recently been changed to become non ordinal types (so, for instance you cannot inc such a value). The discussion is whether this should prevent to put them in a bitset - I personally see no good reason for this (at most we could require an ordinal type for items)

I have an application I'm working on where I get pressed keyboard scancodes from the OS and relay that to a set for convenience - of which my scancode enum has a few holes (as not every value is defined by the standard defined by the USB spec), so having enums with holes work with set[T] is useful to me.

If we do formally allow enums with holes in sets, instead of the internal array's "length in bits" being T.high() + padding or whatever, maybe the internal array's length in bits should be equivalent to just the number of discrete enum fields (again, + any necessary padding), from which we can create some sort of mapping from a bit index to the enum field's real value as a special case for holed enums.

If the restriction is not loosened, then it would be a good idea to also have a flag type.

For the time being, set should continue to accept enums with holes. Working on it.

Still an issue with literals

type Foo = enum
  Foo1 = 0
  Foo2 = 1
  Foo3 = 3

let x = { Foo1, Foo2 } # Error: ordinal type expected

By the way, this is a problem for NimPNG which uses this form here

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juancarlospaco picture juancarlospaco  路  3Comments

hlaaftana picture hlaaftana  路  3Comments

Tronic picture Tronic  路  3Comments

timotheecour picture timotheecour  路  3Comments

koki-koba picture koki-koba  路  3Comments