-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Can/should we take repr seriously? #33260
Comments
I don't really see why --- telling people to handle the flag doesn't seem any worse than telling people to add a particular method. |
Aside: |
A big part of the problem seems to be that it's hard to characterize how array/dataframe elements should be printed in the REPL. They don't need to be parseable, and we want to use a "nice"/non-parseable representation when possible, but we also want to print type info like the |
I believe relying on people to not forget something is a bad idea. People forgetting to define
Isn't it an argument favoring adding an API for |
OK, adding One thing I want to discuss more is, what are the use cases for non-parseable
I think the desired array element printing is very close to: default: Any examples where that would go wrong? And are there any other contexts like this? |
The only reason I can think of is backward compatibility. It would be great if I understand that co-existence of similar APIs is very unsatisfactory. But addition of a new API is the only option I can think of to clean up
I suggest to not include this logic inside array printing. Rather, I think array printer should just set
|
It also should set |
I think we should be using MIME types to control this? |
Yes, we use MIME for that. We briefly used an IOContext flag for it ( |
I think #34387 is a big step for fixing the situation (thanks to fchorney!). Ref: #30901 (comment) But not everything is resolved since Lines 329 to 332 in 1d918dd
That is to say, 3-arg @JeffBezanson You suggested to keep this in #34387 (comment) (just for now?). Is there a plan to improve this? Also, it would be nice if fallback to 2-arg Lines 108 to 111 in 1d918dd
can be removed in a future version of Julia. If 2-arg |
Instead of requiring I can't tell if that punts most of the problem to now serializing expressions into strings, but I do like that it separates it, and I think it addresses #33260 (comment). example: import OffsetArrays: OffsetArray
uneval(x) = quote $x end
function uneval(o::OffsetArray)
p = uneval(parent(o))
a = uneval(axes(o))
oa = uneval(OffsetArray)
quote
($oa)($p, $a)
end
end
a = OffsetArray(rand(3,3), (3:5, 3:5))
@show repr(a)
println("show:")
show(stdout, "text/plain", a)
println()
@show string(uneval(a))
@show eval(Meta.parse(string(uneval(a)))) == a
EDIT: import MacroTools: prewalk, rmlines, unblock
@show string(prewalk(rmlines ∘ unblock, uneval(a)))
|
The current |
Why do we need a textual format that’s round trippable? I have yet to encounter a situation where this necessary. Seems like a very hard and complex requirement to try to satisfy. |
For me, it makes it more enjoyable to use a REPL. I think it's the same justification for why people spend effort making configuration file formats that are both human- and machine-readable. It would let a user print out some complicated nested data structure, be able to select a piece of it, and copy the selction, and paste into the REPL to get an that value. If we weren't beholden to text terminals, and we had smarter terminals with better copy and pasting, then it would likely obviate the need for a format like this, since you could just have a presentation format, and in parallel have an underlying representation that lets you reconstruct the value from the clipboard. |
I get that it’s nice which is why |
As I've explained in the OP,
I think an API that may or may not satisfy some property is rather hard to use because you can't rely on it. That's why I think @mbauman's suggestion for making this opt-in makes sense. |
Again, I'm not saying that it's not nice if the output of Here's an example. How would you define mutable struct X
x::X
function X()
x = new()
x.x = x
end
end Currently we print it like this: julia> x = X()
X(X(#= circular reference @-1 =#)) How would you print this so that the printed expression evaluates back to an equal value? Or what about this array: julia> a = Any[1, 2, 3, 4]
4-element Array{Any,1}:
1
2
3
4
julia> a[3] = a;
julia> repr(a)
"Any[1, 2, Any[#= circular reference @-1 =#], 4]" Do we disallow calling |
I don't think so. It's reasonable (and already done) to support converting arbitrary vega/vega-lite spec back to Julia syntax. For example, you'd want to print a spec as Julia code and then put it in a script so that it can be re-used for different dataset. Saving the original code is not an option since vega-lite spec can be coming from elsewhere like a GUI to construct the spec: https://github.com/queryverse/DataVoyager.jl
As I discussed in the OP, using Serialization is not appropriate sometimes. For example, you can't cross Julia versions or sessions with different sysimages. Also, using Serialization (or something like JSON) is a lot more complicated than constructing code to be executed. I don't think it's appropriate for something like pre-compilation mechanism in
That's why I said opt-in makes sense. Why not do it when it's not super complex?
If we have |
Yes, I don't think anybody here wants a major effort to give all objects parseable representations no matter what. There are a couple cases:
So I think all anybody wants is a mode where 1 & 2 give an error at printing time, and 3 gives you the parseable output even though it's awful. A |
I think a flag would not be enough because an implementer can easily forget about checking |
We slowly get closer over time with |
Currently,
repr
in Julia is maybe evaluatable or parseable or (often) just a string representation only consumable by humans. However, it could be much useful if it is guaranteed to be evaluatable. For example, you can find a lot of examples inbase/loading.jl
which is used as simple IPC mechanism:julia/base/loading.jl
Lines 1148 to 1151 in 9a8b2fd
In case of
base/loading.jl
it is OK to userepr
because the types used there are known to have evaluatablerepr
. However, some basic types likePkgId
cannot be used in this way:Another concrete example I have in mind where
repr
can be useful is to create a plot "spec" using DataVoyager.jl and dump it into a runnable Julia script. Currently, using it needs a rather convoluted invocation likeshow(IOContext(stdout, :compact=>false), "text/plain", spec)
becauserepr
is not a reliable entry point for evaluatable code.We have
Serialization
module for serializing complex Julia objects. Unfortunately, it cannot be used for communicating with different Julia versions. For complex serializations it is probably a good idea to use something like JSON instead of Julia code. However, I think the above examples are good enough motivation to haverepr
for simple cases.It was suggested to add a flag like
parseable
(e.g., #33178 (comment), #30683 (comment)) via theIOContext
mechanism. I have a concern about this direction because it is practically impossible to enforce parsability this way (a brief discussion with @JeffBezanson in #30757 (comment)). I think the overloading API should be clear that the implementer has to make it evaluatable. This can be done by introducing overloading API such asshow(::IO, ::MIME"application/julia", obj)
orrepr(::IO, obj)
.Questions:
IOContext
? New entry point (e.g.,show(::IO, ::MIME"application/julia", obj)
)? Something else?The text was updated successfully, but these errors were encountered: