Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

array display is a mess #6117

Closed
StefanKarpinski opened this issue Mar 11, 2014 · 17 comments
Closed

array display is a mess #6117

StefanKarpinski opened this issue Mar 11, 2014 · 17 comments
Labels
domain:io Involving the I/O subsystem: libuv, read, write, etc. stdlib:REPL Julia's REPL (Read Eval Print Loop)

Comments

@StefanKarpinski
Copy link
Sponsor Member

Recent changes to array printing have made it impossible to normally provide show methods for custom array types. The writemime function intercepts printing of arrays, so that if you define a new type, e.g. Bytes <: AbstractVector{Uint8} and then define show(io::IO, b::Bytes), that show method never gets called. This whole situation is a pretty huge mess, imo. There's no good reason for show and writemime for arrays to produce such different results and you certainly shouldn't have to know about or override writemime methods to get a custom array type to show up the way you want it to in the repl.

@stevengj
Copy link
Member

Didn't a similar problem exist before writemime? Previously, the REPL output called repl_show, which called print_matrix for arrays, as I understand it, rather than show.

Which is not to say that we shouldn't clean up the situation.

One option would be to make writemime call show rather than showarray.

Another would simply be to deprecate show and tell people that they should overload writemime(io, ::MIME"text/plain", x). It seems like, currently, show is for a more "faithful" representation and writemime is for user-readable display, but I'm not sure why this distinction is important since neither text/plain nor show are particularly good formats for data interchange or serialization.

@andreasnoack
Copy link
Member

...or UniformScaling<:AbstractMatrix. I couldn't figure out if there was a new right way to define show methods and therefore ended up defining a showarray method. A show(io,Array) method would have felt more julian to me.

@JeffBezanson
Copy link
Sponsor Member

The purpose of showarray is to pass arguments describing how to print the array, because we want several variants. We have to either live with this or switch to a different mechanism for passing these values.

@JeffBezanson
Copy link
Sponsor Member

See also #5709

@JeffBezanson
Copy link
Sponsor Member

Here's a possible way forward that deals with each of the extra parameters in showarray:

  1. Leave printing headers to writemime, take it out of show
  2. Use a global for limiting output (we have one already)
  3. Call tty_rows and tty_cols to get the screen size if you want
  4. Make the repr and writemime representations more similar, for example
Float32[
 1.0  1.0  1.0
 1.0  1.0  1.0
 1.0  1.0  1.0]

It is very helpful if the "pretty" output and the "useful" (e.g. parsable) output are the same.

@JeffBezanson JeffBezanson added this to the 0.3 milestone Mar 13, 2014
@malmaud
Copy link
Contributor

malmaud commented Mar 13, 2014

This also relates to #5564.

@mcg1969
Copy link

mcg1969 commented Jul 29, 2014

I just happened upon this issue myself. I created a new abstract array type for which I specifically do not want to print the individual values. I had assumed that overloading show would be sufficient, but of course that failed. I eventually discovered that overloading writemime is necessary to accomplish this.

Given that show(io::IO, X::AbstractArray) immediately calls showarray, it's not clear to me why writemime couldn't just call show instead of showarray. In fact, as the code is currently written, in can be. Here are the two functions:

show(io::IO, X::AbstractArray) = showarray(io, X, header=_limit_output, repr=!_limit_output)
writemime(io::IO, ::MIME"text/plain", v::AbstractArray) =
    with_output_limit(()->showarray(io, v, header=true, repr=false))

Because with_output_limit flips the global _limit_output flag, you should get the same results with this implementation---unless show is overloaded, which of course is what i want :-)

writemime(io::IO, ::MIME"text/plain", v::AbstractArray) =
    with_output_limit(()->show(io, v))

@stevengj
Copy link
Member

@mcg1969, that seems reasonable to me.

@diegozea
Copy link
Contributor

I have found this problem when I was defining an AbstractArray. I solved it with a new definition of Base.showarray for my type. Is there another way to do this? Should this be documented in Abstract Array Interface?

julia> N = zeros(ResidueCount{Int, 2, false})
20x20 ResidueCount{Int64,2,false}:
Error showing value of type ResidueCount{Int64,2,false}:
ERROR: MethodError: `ndims` has no method matching ndims(::ResidueCount{Int64,2,false})
 in showarray at show.jl:1205
 in anonymous at replutil.jl:29
 in with_output_limit at ./show.jl:1242
 in writemime at replutil.jl:28
 in display at REPL.jl:113
 in display at REPL.jl:116
 in display at multimedia.jl:151
 in print_response at REPL.jl:133
 in print_response at REPL.jl:120
 in anonymous at REPL.jl:621
 in run_interface at ./LineEdit.jl:1586
 in run_frontend at ./REPL.jl:862
 in run_repl at ./REPL.jl:165
 in _start at ./client.jl:453

julia> show(N)
ResidueCount{Int64,2,false} 
  counts: Array(Int64,(20,20)) [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
  marginals: Array(Int64,(2,20)) [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
  total: Int64 0

@mbauman
Copy link
Sponsor Member

mbauman commented Jul 30, 2015

It's a mess, but it shouldn't be erroring. What's the definition of ResidueCount? You need to pass your eltype and ndims parameters to AbstractArray, e.g.,

immutable ResidueCount{T, N, b} <: AbstractArray{T,N}

@lindahua
Copy link
Contributor

We came across similar problems as to how to properly specialize the show of an array.

I think we need a specific page in the manual explaining how to create a new array type (e.g. what methods need to be defined, and what their behaviors are supposed to be, etc).

@diegozea
Copy link
Contributor

Thanks @mbauman, I wasn't passing my parameters to AbstractArray

@IainNZ
Copy link
Member

IainNZ commented Jul 30, 2015

@lindahua
Copy link
Contributor

Thanks for the pointer. But that part of the document does not mention showarray and other printing related stuff.

@IainNZ
Copy link
Member

IainNZ commented Jul 30, 2015

Correct.

@vtjnash
Copy link
Sponsor Member

vtjnash commented Mar 25, 2016

see #14052 for latest cleanup plans for this

@JeffBezanson
Copy link
Sponsor Member

Fixed by #16354.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:io Involving the I/O subsystem: libuv, read, write, etc. stdlib:REPL Julia's REPL (Read Eval Print Loop)
Projects
None yet
Development

No branches or pull requests