-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
IOContext: introduce the :typeinfo property #24651
Conversation
Nice work! 👍
I think we should always print all digits, except in a context that's clearly for convenient interactive use (i.e. |
Ah OK. So none of the current |
base/arrayshow.jl
Outdated
end | ||
end | ||
|
||
typeinfo_context(io::IO) = get(io, :typeinfo, Any)::Union{DataType,UnionAll} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this wrapper really useful? It makes it actually harder to read the code for people who don't know that it's just a call to get
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with removing it, it's mainly a leftover from my successive re-factorization of the implementation of the new feature. But one thing which I will was addressed is that the default value of attributes (Any
in this case) was set once and for all, instead of repeated at each call site. I have been thinking of defining getindex(io::IO, ::Symbol)
which would take care of that, but it's not clear that it would be the best way.
Thanks for this! Would it be possible to start with a commit which doesn't move code around? It's really hard to review with this large diff... |
I was expecting such request... If you don't mind, I think it would be easier to first move code around and then introduce the functionality. |
c7c03dc
to
ae52c98
Compare
This is now split: the first commit is very basic cut-n-paste from one file to another, and the second implements the new stuff. It's indeed a much easier diff. I realize that I didn't move all the printing-array related functions to the new file (like |
a7df592
to
3aa10c9
Compare
I now added tests and documentation. I still wish to review the whole thing myself at least once, but I think this is in pretty good shape (I will just have to rebase and edit a commit message before merge).
I now just moved one more method of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks quite good in general! Here are my comments.
base/arrayshow.jl
Outdated
|
||
# 0-dimensional arrays | ||
print_array(io::IO, X::AbstractArray{T,0} where T) = isassigned(X) ? | ||
show(io, X[]) : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unusual indentation.
print_array(io::IO, X::AbstractArray) = show_nd(io, X, print_matrix, true) | ||
|
||
# typeinfo aware | ||
# implements: show(io::IO, ::MIME"text/plain", X::AbstractArray) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this called _display
if it implements show
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because basically this method of show
is what is invoked by display
, whereas calling show(object)
prints something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call it _showtextplain
, then? It's not only called by display
, nor is it necessarily called by display
(depends on the Display
), and confusing display
overloading with show
overloading is a perennial problem.
Not sure what was wrong with the old showarray
, though… can't we leave the name as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rfourquet Bump!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, the old showarray
was doing mainly two distinct things, which have been separated out into two distinct functions here, so it made sense to use new names: otherwise which one should inherit the old name? But maybe there is an easy answer (which also doesn't break code which may have used this function)? (I can't look at this right now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was already fixed in #25775
base/arrayshow.jl
Outdated
io = IOContext(io, :typeinfo => eltype(X)) | ||
|
||
# 1) print summary info | ||
print(io, summary(X)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not your code, but this should use summary(io, X)
to allow summary
to use IOContext
information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I had to fix that in #23806 too.
base/arrayshow.jl
Outdated
|
||
### non-Vector arrays | ||
|
||
# _show & _show_empty: main helper function for show(io, X) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"functions"
base/arrayshow.jl
Outdated
|
||
# NOTE: it's not clear how this method could use the :typeinfo attribute | ||
_show_empty(io::IO, X::Array{T}) where {T} = print(io, "Array{$T}(", join(size(X),','), ')') | ||
_show_empty(io, X) = nothing # by default, we don't know this constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better print an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may be right, but I'm not sure. I think I prefer to not change this behavior here (which is the current one in master), and tackle this in a separate PR if the right thing to do is found.
test/nullable.jl
Outdated
@@ -102,6 +102,8 @@ for (i, T) in enumerate(types) | |||
showcompact(io2, get(x3)) | |||
@test String(take!(io1)) == @sprintf("Nullable{%s}(%s)", T, String(take!(io2))) | |||
|
|||
# these tests are disabled rather than fixed, because Nullable is to be removed from base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just leaving a note so that we don't forget it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just that I left that comment so that it's obvious to everybody that this shouldn't be merged until Nullable
has been removed so that we don't leave these commented out tests.
@@ -70,7 +70,7 @@ end | |||
@test ===(eltype(s3), Float32) | |||
end | |||
@testset "show" begin | |||
@test sprint(show, Set()) == "Set{Any}()" | |||
@test sprint(show, Set()) == "Set(Any[])" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that change is an improvement. Maybe that allows simplifying the code, but Set{Any}
is really the information that should be printed AFAICT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set{Any}
is really the information that should be printed AFAICT.
Why do you think so? I find it more regular (and preferable) to always print Set(array-form)
than resorting to Set{T}()
only when it's empty, and as you said it simplifies the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, OK. I thought we printed e.g. Set{Real}([1, 2]}
, but since that's not the case I guess it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the printing may predate being able to write it that way, maybe we should change it to that instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Though probably better left for a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got used to the printing Set(array)
! and on a not so serious note, it's more compact, we save 2 characters! But yes I would prefer to leave that to anther PR.
test/show.jl
Outdated
@test showstr(Set([[Int16(1)]])) == "Set(Array{Int16,1}[[1]])" | ||
@test showstr([Float16(1)]) == "Float16[1.0]" | ||
@test showstr([[Float16(1)]]) == "Array{Float16}[[1.0]]" | ||
@testset "nested Any eltype" begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to test with other abstract types like Real
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The specifity of Any
(compared to an abstract type in general) is that a collection is isa Any
and its elements are also isa Any
, and I don't know which other type would satisfy this. But I can of course add a test for Real
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I was thinking about the Any
special case (see my comment).
base/show.jl
Outdated
@@ -61,6 +61,11 @@ The following properties are in common use: | |||
- `:displaysize`: A `Tuple{Int,Int}` giving the size in rows and columns to use for text | |||
output. This can be used to override the display size for called functions, but to | |||
get the size of the screen use the `displaysize` function. | |||
- `:typeinfo`: a type specification characterizing the information already expressed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"type specification" is a bit vague. Maybe "A Type
"? "expressed" could be "printed".
base/show.jl
Outdated
@@ -61,6 +61,11 @@ The following properties are in common use: | |||
- `:displaysize`: A `Tuple{Int,Int}` giving the size in rows and columns to use for text | |||
output. This can be used to override the display size for called functions, but to | |||
get the size of the screen use the `displaysize` function. | |||
- `:typeinfo`: a type specification characterizing the information already expressed | |||
concerning the type of the object about to be displayed. This is mainly useful when | |||
displaying a collection of object of the same type, so that redundant type information |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"objects". Close the parentheses.
Maybe a simpler example would be easier to understand, e.g. with [Float16(1)]
? The text should say what's the value of the argument in that case.
Thanks @nalimilan for your review! I updated accordingly, except for the "compact printing" `Float16" which is not sorted out yet. |
Looks like this PR has been kind of forgotten. Could you rebase it and squash the commits, except the one which just moves code around? That will make it easier to review and ready for merging. |
Thanks for reviving it! but I had understood your comment as meaning that this depends on your PR which replaces |
Yeah, I guess I hoped it would take less time to merge my PR. You could just remove |
Would it be possible to separate the commits into code motion versus changes? I find it a bit hard to review in the current state with code motion and changes combined. Either order is fine. |
3c95afb
to
2cb6a3d
Compare
Squashed all but the first commit, which strictly only moves some code to the new "arrayshow.jl" file, should be easier to review now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very nice – thanks for making the change. It's great to have type info only displayed when it's not redundant!
Thanks! |
Agree, this code is not performance-critical so no harm in leaving the assertion in there. Better to know about our bugs than remain clueless. |
From my perspective this is good to go, so please feel free to merge this when you see fit. |
Ok, I will keep it open a couple of days before re-squashing and merging. |
Why wait that long? It's been open for comment for a while already. It's not like the idea is controversial – it's pretty clearly the right way to go. |
Mainly to give @nalimilan the time to review if he wanted, as he is the one having requested to squash... but he had reviewed already, so you are right, I won't wait so long! (at least just to have again CI green). |
6c92664
to
76b83f0
Compare
base/arrayshow.jl
Outdated
|
||
### non-Vector arrays | ||
|
||
# _show_nonemtpy & _show_empty: main helper functions for show(io, X) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"_show_nonempty". Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catches! Thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me apart from the few details I just noted. BTW, there's also a typo in the commit title: "IOContex".
base/arrayshow.jl
Outdated
end | ||
end | ||
# a specific call path is used to show vectors (show_vector) | ||
_show_nonemtpy(::IO, ::AbstractVector, ::String) = error("_show_nonemtpy(::IO, ::AbstractVector, ::String) is not implemented") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Break at 92 characters?
base/arrayshow.jl
Outdated
# similar to `eltype`, but in some cases this would lead to incomplete | ||
# information: assume we are at the top level, and no typeinfo is set, | ||
# and that it is deduced to be typeinfo=Any by default, and consider | ||
# printing X = Any[1]; to know if the eltype of X is already diplayed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"displayed"
show_vector(io, s, "[", "]") | ||
print(io, ")") | ||
print(io, "Set(") | ||
show_vector(io, s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we have print_array
but show_vector
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not good at naming, and I forged them on top of what was existing, but the print_array
work for any array, while show_vector
is a special method implemented only for 1-D collections, which is meant (as this example show) to be used beyond the array case. I just didn't change the original name for this one, and I can't think of a clearly better one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean that the discrepancy between "show" and "print" is weird, unless there's a reason for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean in those two lines? there I just kept it how it was, and show
ing a String
will print the quotes. But you refered to print_array
, which is just an internal name basically implementing the logic of display
, so it's not so important (print_array
comes from the pre-existing print_matrix
function). Sorry I'm still not clear exactly what you think should be changed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I thought you had renamed one of them. Carry on...
76b83f0
to
8a0c710
Compare
Before, the :compact property was conflating 2 concepts: 1) are we low on screen space? 2) can we skip printing individual type information for elements in a collection? Now, :compact controls only 1), while :typeinfo controls 2). Cf. #22981 for context and discussion. Credit to Stefan Karpinski for the formulation of the design implemented here.
8a0c710
to
fe6709b
Compare
Wow all green, rare anough to be worth mentioning :D |
Looks like the docstring for
|
Before, the
:compact
property was conflating 2 concepts:Cf. #22981 for context and discussion. Credit to Stefan Karpinski for the
formulation of the design implemented here.
</end commit message>
So this tackle only the redundancy in type information, not the number of digits of array elements to print (refered to as
:sigdigits
in the linked PR).Here is a short demo:
I didn't update here the
show
method for every object which could take advantage of this new attribute, but this can be done incrementally.Also, as my editor (emacs) had trouble indenting the "show.jl" file because it's too big, editing this file was a nightmare, so I put the method related to showing arrays in a new file, "arrayshow.jl", which I believe is a better organization anyway, regardless of my editing comfort. The code was quite entangled, with non-consistent function names, so I had also to refactor to have a chance to understand the interaction between the functions and to include the new feature (I'm fine of course with suggestions for naming).
The main refactoring change is that I deleted the labyrinthic
showarray
method, which had 2 options:repr
andheader
. By tracing how it was called in base, it appeared that basically 2 independant code paths were used depending on the combination of those 2 options, so the most sane action was to split it into 2 distinct methods, which implementshow
anddisplay
. The result is a bit less powerful (not possible to callshowarray(io, X, false, header=false)
, but in the case were this was needed in base (for printing invalid strings), this was equivalent toprint_array(io, X)
(which doesn't know about:typeinfo
, but this is fine forUInt8
elements).TODO:
IOContext
's docstring (but there are already some explanatory comments in the new file)alignment
in the first commit