I’m trying to understand the below behaviour (MWE reduced from a larger set of code). I define an alias for
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.
# 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)))")
mutable struct S
n::UInt8 # Type is UInt8, not CompositeValue
@printf("in constructor: %s\n", v)
When I run the code above in Julia 1.5.2 the output is
in constructor: 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
S is influenced by my (re)definition of
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…
Use a wrapper type, eg
I kind of dismissed that idea earlier as being somewhat convoluted, but it indeed works out quite nicely.
Any clue as to why the overrridden
Base.show() isn’t called in all cases?
I think it’s because
Printf.print === Base.print:
julia> @macroexpand @printf("%s\n", 0x04)
which in turn calls
julia> @code_lowered Printf.print(stdout, 0x04)
1 ─ %1 = Base.string(n)
│ %2 = Base.print(io, %1)
└── return %2
All the functionality for formatting and printing is a bit messy imho (
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
show, but apparently it does so with the
print(io::IO, n::Unsigned) method.
The documentation says:
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.
@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.
julia> show(stdout, 0x4)
julia> print(stdout, 0x4)
I think I’ve learned something today Thanks!