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...
@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.
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()]