Some time the compiler does what you want and then it just doesn't! This happens when running one or more lines of code and then when you run it again there's an issue. For example:
# worked
type byte = range[uint8(0)..uint8(128)] # or just uint8 without the range
type bytearray[H: static uint64] = array[uint64(0)..H, byte]
const b: byte = 'a'
const ba: bytearray[1] = [0x80, b]
Then when I tried to run it again (about 5 times), it just didn't work. I kept getting an error about the char 'a'. Even when I supplied 'a'.byte, it worked at first, then everything went downhill after trying to run the code again. This also happens for a lot of my other programs as well. Can someone pleeeeease tell me why this is happening?I don’t see how this program can compile.
Here is a version which compiles:
# worked
type byte = range[uint8(0)..uint8(128)] # or just uint8 without the range
type bytearray[H: static uint64] = array[uint64(0)..H, byte]
const b = byte('a')
const ba: bytearray[1] = [byte(0x80), b]
First, when defining “b” you need to convert 'a' to a “byte” as you explained in your comment.
Then, when defining “ba” you need to convert 0x80 to a “byte” in the array literal. If you don’t specify that the first value is a “byte”, then the array is expected to contain values of the same type as the first one, which is of type “int”. As the second value is of type “byte", there is a mismatch.
Would the below code work?
type byte = range[uint8(0)..uint8(128)] or char
Okay, so the below code works for the byte type:
type byte = range[uint8(0)..uint8(128)] or range[0x00..0x80] or char
but for the bytearray, because a normal nim array doesn't know what my byte type is and a hex or char is already known, they need to be explicitly converted to a byte. Meaning when a pass a hex or char value to the array they're going to be seen as they are. Also my bytearray doesn't know how to handle anything of type byte. Is there a way I could accomplish this using concepts?
It seems that you want to define arras containing values of different types. This is not possible in Nim and it doesn’t matter if the type is already known (predefined) or not.
When you use the union operator or to define the type “byte”, it means that you can define a common behavior for variables, constants, parameters of type range[uint8(0)..uint8(128)], range[0x00..0x80] or char. It doesn’t mean that you can mix values of these types, either when assigning them, comparing them or grouping them in an array.
And when using a value of “abstract” type “byte”, you have to make sure that its actual concrete type is known at compile time. You can write generic code using “byte”, but anyway, values must finally be of a concrete type with the restrictions enforced by a statically and strongly typed language.
I don’t use concepts, but this is only a way to raise the level of abstraction and they don’t allow to override the fundamental constraint regarding value types.
To avoid the explicit conversions, you could use converters, but I don’t know how they behave when defining values in an array.
And to conclude, the Nim way to mix values of different types consists to use object variants. But it seems a bit overkill in this case.
converter toByte(c: char): uint8 = uint8(c)
converter toBytes[N](a: array[N, int]): array[N, uint8] =
for i, v in a:
result[i] = uint8(v)
var
x: uint8 = 'a'
arr: array[4, byte] = [0x0a, 0x0b, 0x0c, 0x0d]
echo x # 97
echo arr # [10, 11, 12, 13]