Currently calling @define_integers defines Base.widen to be BigInt if the type with twice the bits does not exist yet.
This is unfortunate in my opinion:
using BitIntegers
@define_integers 24
@define_integers 48
widen(Int24)
results in BigInt, whereas (in a new REPL)
using BitIntegers
@define_integers 48
@define_integers 24
widen(Int24)
results in Int48.
The order of type definitions in Julia typically can make the difference between a valid and an invalid program (Exception), but does not implicitly change the program. Here we have an implicit effect on runtime, memory (e.g. going from 3 byte (4 bytes depending on how you count) for Int24 to 16 bytes for BigInt) and result in addition to the unintuitive behavior. I think at the very least this behavior should be prominently documented.
However, I think the current implementation is even more problematic. The documentation of widen states
If x is a type, return a "larger" type, defined so that arithmetic operations + and - are guaranteed not to overflow nor lose precision for any combination of values that type x can hold.
Therefore, I think the natural result of widen(Int24) according to the citation is Int32. However, if you want to multiply two arbitrary Int24s, you probably want to widen either to Int48 or to Int64. It won't get easier if you think about what widen should do for Int40, Int48 and Int56: Depending on the situation it should either be the next 8 bit larger type, Int64, the type with twice the number of bits, Int128 or BigInt.
In addition, the documentation contains this ambiguous sentence
For fixed-size integer types less than 128 bits, widen will return a type with twice the number of bits.
I am pretty sure that this is meant as
For predefined fixed-size integer types less than 128 bits, widen will return a type with twice the number of bits.
We can get that changed, I think.
The main problem of the current implementation is that the methods are defined by the macro call and therefore in the caller's namespace. Therefore, the user can't define widen themself. I therefore suggest to not define widen at all in @define_integers and instead provide examples in the documentation how the user can define it depending on their needs.
Currently calling
@define_integersdefinesBase.widento beBigIntif the type with twice the bits does not exist yet.This is unfortunate in my opinion:
results in
BigInt, whereas (in a new REPL)results in
Int48.The order of type definitions in Julia typically can make the difference between a valid and an invalid program (Exception), but does not implicitly change the program. Here we have an implicit effect on runtime, memory (e.g. going from 3 byte (4 bytes depending on how you count) for Int24 to 16 bytes for BigInt) and result in addition to the unintuitive behavior. I think at the very least this behavior should be prominently documented.
However, I think the current implementation is even more problematic. The documentation of
widenstatesTherefore, I think the natural result of
widen(Int24)according to the citation isInt32. However, if you want to multiply two arbitraryInt24s, you probably want towideneither toInt48or toInt64. It won't get easier if you think about whatwidenshould do forInt40,Int48andInt56: Depending on the situation it should either be the next 8 bit larger type,Int64, the type with twice the number of bits,Int128orBigInt.In addition, the documentation contains this ambiguous sentence
I am pretty sure that this is meant as
We can get that changed, I think.
The main problem of the current implementation is that the methods are defined by the macro call and therefore in the caller's namespace. Therefore, the user can't define
widenthemself. I therefore suggest to not definewidenat all in@define_integersand instead provide examples in the documentation how the user can define it depending on their needs.