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.
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)
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...
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.
import typetraits var x: tuple[a, b, c: int, d: string, e: int64] echo type(x).arity
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()]