Showing a BitVector in NamedTuple

I find a bit of inconsistency, probably about showing a NamedTuple

julia> v = [1, 0, 1.];

julia> nt = (bitvec = Bool.(v),) # the following output is not accurate
(bitvec = Bool[1, 0, 1],)

julia> nt.bitvec
3-element BitVector:
 1
 0
 1

julia> nt.bitvec::Vector{Bool}
ERROR: TypeError: in typeassert, expected Vector{Bool}, got a value of type BitVector
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

julia> bitvec = Bool[1, 0, 1]
3-element Vector{Bool}:
 1
 0
 1

julia> bitvec::Vector{Bool}
3-element Vector{Bool}:
 1
 0
 1

could this be somehow improved?

The issue is not necessary related to NamedTuples. It’s simply that the short form representation of a BitVector is Bool[...]:

julia> println(nt.bitvec)  # show(stdout, nt.bitvec)
Bool[1, 0, 1]

julia> display(nt.bitvec)  # show(stdout, MIME("text/plain"), nt.bitvec)
3-element BitVector:
 1
 0
 1

I would assume it’s possible to change this to e.g. BitVector[1, 0, 1] without too much trouble.

See also Show container type by default when showing AbstractArrays that are not Arrays by LilithHafner · Pull Request #48829 · JuliaLang/julia · GitHub.

2 Likes

So long as this is not executable, why not Bit[1, 0, 1].
In this way we know it is something other than Bool[1, 0, 1].

1 Like

There isn’t a requirement for print-ed expressions to evaluate to an equal object or at all, even if it would be preferable. For AbstractArrays, they seem to prioritize the element type and values over the exact concrete type.

julia> Number[1,2.2] |> println
Number[1, 2.2]

julia> Number[1,2.2] |> display
2-element Vector{Number}:
 1
 2.2

julia> SVector{2}(Number[1, 2.2]) |> println
Number[1, 2.2]

julia> SVector{2}(Number[1, 2.2]) |> display
2-element SVector{2, Number} with indices SOneTo(2):
 1
 2.2

I disagree with these because the appearance of array literals imply an element type of BitVector or the nonexistent Bit, and the expressions throw errors if evaluated. Bool.([1, 0, 1]) or BitVector([1, 0, 1]) (as suggested in the linked issue) both do that job now, but I’m concerned that’s unreliable or misleading somehow.

3 Likes

Also, there is

julia> v = BitVector([1, 0, 1]); show(v)
Bool[1, 0, 1]

The docstring for show (with one argument) says:

The representation used by show […] should be parseable Julia code when possible.

I find the possibility to generate parseable output very useful – more precisely, parseable output that reproduces the argument to show. I think show(v) should give BitVector([1, 0, 1]) in this case.

4 Likes

If we’re talking more about reflection than printing, it’s worth pointing out that dump recursively digs into structs to a maxdepth (default 8) until printing a few types of values, possibly in arrays.

julia> struct Blah
         b::BitVector
         c::Complex{Int}
       end

julia> Blah([1,0], 1im) |> println # default to the Bool[] issue
Blah(Bool[1, 0], 0 + 1im)

julia> Blah([1,0], 1im) |> display
Blah(Bool[1, 0], 0 + 1im)

julia> Blah([1,0], 1im) |> dump
Blah
  b: BitVector
    chunks: Array{UInt64}((1,)) UInt64[0x0000000000000001]
    len: Int64 2
    dims: Tuple{Int64}
      1: Int64 6
  c: Complex{Int64}
    re: Int64 0
    im: Int64 1

Note that dump still runs into print for some structs like Complex in arrays, which is not the default behavior.

julia> Complex{Int}.(1:2, 1:2) |> dump
Array{Complex{Int64}}((2,)) Complex{Int64}[1 + 1im, 2 + 2im]

julia> struct MyComplex{T}
         re::T
         im::T
       end

julia> MyComplex{Int}.(1:2, 1:2) |> dump
Array{MyComplex{Int64}}((2,))
  1: MyComplex{Int64}
    re: Int64 1
    im: Int64 1
  2: MyComplex{Int64}
    re: Int64 2
    im: Int64 2

Why though? I don’t think getting the type to match is worth the extra method and line noise.

I think that for testing and debugging it’s helpful if one can show any variable in a form that one can feed back to Julia via copy-paste. This function may or may not be named show. Unlike for the other variants of show, the goal would not primarily be readability by users.