I’m trying to understand the below behaviour (MWE reduced from a larger set of code). I define an alias for UInt8 called CompositeValue with the intention of storing two values of 4 bits in a single UInt8 in such a way that I can use CompositeValue where it makes sense. I realize that CompositeValue is merely a different name for type UInt8 and might not work as I intend, but will come back to that below.
using Printf
# type = 4 high bits, value = 4 low bits
const CompositeValue = UInt8
type(a::CompositeValue) = a >> 4
value(a::CompositeValue) = a & 0x0f
function Base.show(io::IO, a::CompositeValue)
print(io, "CompositeValue($(type(a)), $(value(a)))")
end
mutable struct S
n::UInt8 # Type is UInt8, not CompositeValue
function S(v::UInt8)
@printf("in constructor: %s\n", v)
return new(v)
end
end
@printf("%s\n", 0x04)
@printf("%s\n", S(0x04))
When I run the code above in Julia 1.5.2 the output is
4
in constructor: 4
S(CompositeValue(0, 4))
I can’t figure out why there isn’t a consistent printing of either the literal integer or as a CompositiveValue(x,y) in three cases? Somehow only the printing of the UInt8 in S is influenced by my (re)definition of Base.show for UInt8/CompositeValue, but not the other two.
Second question is whether there is a better way to have a type CompositeValue that consists of two 4-bit values in Julia? In C/C++ I would use a bitfield. I found BitsFields.jl, but that doesn’t seem to have been updated for at least 9 months, making me a bit wary to use it. Any other way to have a custom type that is not a struct for such values? Also, the overloading of printing a UInt8 isn’t particularly nice…
All the functionality for formatting and printing is a bit messy imho (show, display, repr, print, string, String, Printf, …). Lots of options, redundancy and source of confusion. Then you have also MIME types and IO context (such as :compact => true). I’m not sure why print bypasses show, but apparently it does so with the print(io::IO, n::Unsigned) method.
print falls back to calling show , so most types should just define show . Define print if your type has a separate “plain” representation. For example, show displays strings with quotes, and print displays strings without quotes.
And @less print(stdout, 0x4) leads us to the following definitions:
show(io::IO, n::Unsigned) = print(io, "0x", string(n, pad = sizeof(n)<<1, base = 16))
print(io::IO, n::Unsigned) = print(io, string(n))
Conclusion: unsigned numbers can be printed decorated with 0x0... or undecorated. The undecorated version is defined with print, and that’s what is used by @printf("%s", ...) so you will have to define print for your type if you want to override this.