Units, errors and type display

question

#1

So it finally happened, I ran out of terminal screen to scroll up through all the Unitful types and find what my error was.

Before I look into changing the memory buffer on my terminal, or log everything to file, can we actually fix this somehow?

How do we use units (or any other super complicated types) and have sensible error output without pages of frustrating scrolling?


#2

What do you propose? Limiting the output would miss some, which would affect the users looking precisely for those.

Look at tmux, or run the REPL in an interface which supports more output (eg Emacs, Juno, …).


#3

Better type-printing tools are on the way in 0.7 via showarg: https://github.com/JuliaLang/julia/issues/18909
It doesn’t look like it’s been added to the online docs just yet, but it’s in the REPL help:

showarg(io::IO, x, toplevel)

Show x as if it were an argument to a function. This function is used by
summary to display type information in terms of sequences of function calls
on objects. toplevel is true if this is the direct call from summary and
false for nested (recursive) calls.

The fallback definition is to print x as ":::(typeof(x))", representing
argument x in terms of its type. (The double-colon is omitted if
toplevel=true.) However, you can specialize this function for specific types
to customize printing.

Example
≡≡≡≡≡≡≡≡≡

A SubArray created as view(a, :, 3, 2:5), where a is a 3-dimensional Float64
array, has type

SubArray{Float64,2,Array{Float64,3},Tuple{Colon,Int64,UnitRange{Int64}},false}

The default show printing would display this full type. However, the summary
for SubArrays actually prints as

2×4 view(::Array{Float64,3}, :, 3, 2:5) with eltype Float64

because of a definition similar to

  function Base.showarg(io::IO, v::SubArray, toplevel)
      print(io, "view(")
      showarg(io, parent(v), false)
      print(io, ", ", join(v.indices, ", "))
      print(io, ')')
      toplevel && print(io, " with eltype ", eltype(v))
  end

Note that we’re calling showarg recursively for the parent array type,
indicating that any recursed calls are not at the top level. Printing the
parent as ::Array{Float64,3} is the fallback (non-toplevel) behavior,
because no specialized method for Array has been defined.


Broadcasting in 0.7
#4

I was semi serious, but really trying to make the point that if I have to look at using a different terminal it might not be the terminal that’s the problem. The scrolling will be painful wherever it happens.

I think being able to change the nesting depth of type output could help, if thats possible. I really only need to see the top two levels most of the time.

@stillyslalom showarg looks good - but is it actually called for error output? That’s the main pain point with Unitful.


#5

I have definitely seen error-messages (in fact using DifferentialEquartions + DynamicHMC) which were well beyond what I can parse, containing 100s of lines of parametrized types. So, whilst there should probably be an option to be able to see all of this, I’d think for normal day to day use, truncating show of parametrized types to say one level would be more helpful.


#6

Perhaps show short form in interactive mode and save the error message so one could do something like REPL.reshow_error() which would print the last error verbosely?


#7

That seems perfect.

Short-form errors by default would save all the scrolling. What I mostly need to see is what the error was, and a traceback of the lines of code that lead to it. Currently these can be separated by pages of type signature.

For the 2% of the time all the types are needed reshow_error() is there. How easy it that to implement?


#8

Pretty easy. The previous backtrace is already stored for the Ctrl+Q keyboard shortcut to jump with the editor to stack frames. Would just need to store the exception as well. Also, would need some option to how types are shown.


#9

Should I open an issue somewhere for this?


#10

For the record my error clocks in at 1042 lines, 515505 Chars!! About 5000 lines in the terminal.

We could make some kind of competition out of this…


#11
julia> f() = g(); g() = f(); f()

80 000 lines. Do I win?


#12

Hmm. We might have to factor in information content into the ranking, maybe maxium Kolmogorov complexity per error message?


#13

Or length after gzip?


#14

Good point. Type parameters can get very complex even with few levels of nesting.


#15

Could you provide a bit more information about what the bad case is? Is there really a single type that’s 5000 lines long?

Truncating backtraces, and/or better detection of cycles would certainly be good.


#16

There are probably a few lines of backtrace, but yes its hundreds of lines for one type. There’s a struct with maybe 200 params/vars. It’s a pretty complicated biophysical model with units on everything, maybe no-one has pushed units this far yet…

Heres a gist with the gory details, discourse can’t handle it all…


#17

Ok, I’m impressed. :star_struck:


#18

:popcorn:.

I have seen some stuff with users where dimensions end up with big types, but I think you take the cake here. And it solves just fine and just doesn’t plot? The type system never ceases to amaze me…

But yes, there must be some easier way to parse this. I really like the Juno tree displays and would like to see them as part of the Base display system, but of course they wouldn’t be usable from the REPL (I think?)


#19

I’ve handled this manually (because the Strs types can also get fairly gnarly), by adding show methods for them, so at least the specific concrete types that people are meant to use (ASCIIStr, UTF8Str, UniStr, etc.) don’t end up being more than one line.


#20

Yeah solves just fine. It plots if I separate sol out manually, I just need to deal with the timestep handling in that DiffEq/UnitfulPlots recipe somehow.

We are talking about eventually porting some huge Fortran models to Julia in a similar way, so there are better/worse things to come. Unitful is essentially a free API for modularity, it’s going to be one of Julias biggest selling points in environmental modelling fields, along with numerical tools like DiffEq, and an actually nice language…