type Units* = SomeUnsignedInt BitVecS*[S:static int, B:Units = uint] = object Base*: array[S div (sizeof(B) * 8) + int(S mod (sizeof(B) * 8) != 0), B] #8,16,32,64 BitVec*[B:Units] = object Base: seq[B] size: int AnyBitVec[S:static int, B:Units] = (BitVecS[S, B] | BitVec[B]) proc `[]`*[S,B](bv:AnyBitVec[S, B], i:int): int = return (bv.Base[i div (B.sizeof * 8)] shr (i and (B.sizeof * 8 - 1)) and 1).int func newBitVector*[B](size: int, init = 0): BitVec[B] {.inline.} = var blocks = size div (sizeof(B) * 8) + int(size mod (sizeof(B) * 8) != 0) result.Base = newSeqOfCap[B](blocks) result.Base.setlen(blocks) result.size = size var bv1: BitvecS[20240001] var y = newBitVector[uint32](1000) discard y[0] #this fails Run
I am trying to write a bitvector lib that has a common implementation for static (array) and dynamic (seq) ones, with user defineable base unit of storage. For static one I need S (static size) and B (base unit), while for the dynamic one I only need B. I tried like in the code above, but when accessing any procs on the dynamic one (BitVec), I get "Error: cannot instantiate: 'S'". I thought this would work since BitVec doesn't have/need S, but no. I got around it by adding the S parameter to the type, and passing a random number as generic parameter when calling procs on it, and while this works, it's obviously not pretty, and makes me believe there has to be a way to make this work cleanly. I was told to use concepts, but I couldn't make that work either, and I really don't understand how they work even after reading the doc. But I'd like not to use them unless absolutely necessary. Also, on a side note, the default generic parameter type I have on BitVecS (B:Units = uint) seems to actually work, although I was told it shouldn't. Any idea why it works (in this context)?