Is there a way to get number of elements inside a tuple? This is known at compile time, of course; as tuples are fixed structures.

At first glance, this probably sounds like an odd request, but i'm writing macro for an inheritable framework with objects referencing other inheritable objects. And it would be of convenience to the user of the framework if this were resolved without the need for human counting. One less mistake to make and debug.

Not a deal breaker, of course. Just fewer "oops I forgot to change that" mistakes.

2018-05-13 03:15:19
def

Like this using system.fields https://nim-lang.org/docs/system.html#fields.i,S,T :

proc numFields[T](x: T): int =
  for _ in x.fields:
    inc result

var x: tuple[a, b, c: int, d: string, e: int64]
echo numFields(x)

2018-05-13 04:12:52

Actually, since I'm bugging you all with a question, i'll jump into some detail for feedback:

The framework is for turn-based games. A Game object handles "different" kinds of players. The default ConsolePlayer is a "human sitting at the text console". So, if

var move = player.get_move()

is called, then the next move is returned as a string key by prompting the person running the program with text prompts. But if NegamaxPlayer, then 'get_move' runs and negamax AI algo. Or if the framework user creates a GodotPlayer, it might be grabbed from GUI responses. And so on. The idea is consistent responses for methods, but wildly varying means of getting the data.

Anyway, I can't have a list of n players in a sequence because I need to mix/match ConsolePlayer, NegamaxPlayer, etc. in that list. But I need to keep track of the player numbers. So it need to behave like a multi-type list rather than array or seq. But, to my knowledge, that really isn't possible in a compiled language.

So, I'm doing:

  Game* = ref object of RootObj
    # ... stuff removed ...
    player_count*: int
    players*: tuple[
      a: Player,
      b: Player,
      c: Player,
      d: Player,
      e: Player,
      f: Player
    ]
    current_player_number*: int
    # ...

The framework user would then override the tuple with their own variant:

type
  MyCrazyGame* = ref object of Game
    # ...
    player_count*: int
    players*: tuple[
      a: ConsolePlayer,
      b: NegamaxPlayer,
      c: RemoteServerPlayer,
      # ...
    ]
    current_player_number*: int
    # ...

Which is ... arduous to deal with. But okay. Lot's of if/elif sequences to call the same method name in key places.

But before I go down this path too far; is this the best and most nim-like way to do this? Or am I missing something...

Thanks for any feedback on this...

2018-05-13 04:14:22

@def,

Thanks!

In fact, now that I'm browsing the "system" module ... I do believe I'll be sitting back on the couch reading the "system" module doc in depth tonight.

2018-05-13 04:24:40
import typetraits

var x: tuple[a, b, c: int, d: string, e: int64]
echo type(x).arity
2018-05-13 11:37:03

But, to my knowledge, that really isn't possible in a compiled language.

It is possible, you can either use 'case objects':

# A
type
  PlayerKind = enum pkHUMAN pkCPU
  Player = object
    case kind: PlayerKind
    of pkCPU:
      level: int
    else:
      discard

let list = @[Player(kind: pkHUMAN), Player(kind: pkCPU)]
Or ref objects + inheritance:
# B
type
  Player = ref object of RootObj
  PlayerHuman = ref object of Player
  PlayerCPU = ref object of Player

let list = @[PlayerHuman().Player, PlayerHuman(), PlayerCPU()]

2018-05-15 07:50:06
Might come in handy: https://github.com/yglukhov/typelists. At least it provides typeListLen
2018-05-15 09:09:25