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

print the type parameter of Nullable #14304

Merged
merged 1 commit into from
Dec 16, 2015

Conversation

bicycle1885
Copy link
Member

This fixes show{T}(io::IO, x::Nullable{T}) to always show the type parameter of a Nullable object.

Before:

julia> Nullable(1)
Nullable(1)

After:

julia> Nullable(1)
Nullable{Int64}(1)

Though there may be a deep consideration in the current behavior, I think showing type parameters is a conventional way in Julia.

@nalimilan
Copy link
Member

Well, I think the reason why it's not printed is that it's quite verbose and obscures the value. 1 is printed without its type at the REPL, so why would Nullable(1) print the type of 1? Note that when the Nullable is missing (e.g. Nullable()), then the type is shown because it cannot be guessed from the value.

@tkelman
Copy link
Contributor

tkelman commented Dec 7, 2015

I like it better with the type parameter personally. We show the element type parameter with arrays.

@nalimilan
Copy link
Member

Yes, but for arrays it makes sense to have an abstract type for element type. It also greatly affects the behavior of the array, which justifies printing it. For Nullable, there little use in creating a Nullable{Integer}(1).

Finally, the ratio (type information)/contents is quite higher for a one-value object like Nullable.

@bicycle1885
Copy link
Member Author

@nalimilan I see your points; this may look a little bit verbose and if Nullable is a thin wrapper of a value there may be no reason to print its type.

But I think we should stick to the principle of least astonishment in this case. The docsting of show states that the representation should include type information. And as @tkelman pointed out, other container-like types print this kind of type information.

help?> show
search: show showall showerror showcompact @show Cshort Cushort print_shortest

  show(x)

  Write an informative text representation of a value to the current output stream. New
  types should overload show(io, x) where the first argument is a stream. The
  representation used by show generally includes Julia-specific formatting and type
  information.

@nalimilan
Copy link
Member

"Least astonishment" doesn't help you here, as show(1) doesn't print type information. Also note that the docs don't say "should", but "generally". I guess the philosophical issue here is whether Nullable is a value or a container.

@jakebolewski
Copy link
Member

Ref prints the type parameter as well, in addition to almost all container or wrapper types in Base.

@ScottPJones
Copy link
Contributor

Just printing Nullable(1) can lose information, as seen by the following examples:

julia> Nullable{Int8}(1)
Nullable(1)

julia> Nullable{Int128}(1)
Nullable(1)

julia> Nullable{UInt8}(1)
Nullable(0x01)

julia> Nullable{UInt16}(1)
Nullable(0x0001)

@nalimilan
Copy link
Member

Yeah, but just like Int8(1) and Int64(1) print the same. Does anybody argue to print them as 1::Int8 and 1::Int64?

@nalimilan
Copy link
Member

CC: @johnmyleswhite @davidagold

@IainNZ
Copy link
Member

IainNZ commented Dec 7, 2015

+1 to the printing the type, and I think it can be justified through consistency, as Nullable is somewhat container-like and we print the type parameters for containers.

@eschnett
Copy link
Contributor

eschnett commented Dec 7, 2015

Non-trivial values will output their own type anyway, so this will print the type twice in many occasions:

julia> Nullable([1 2; 3 4])
Nullable(2x2 Array{Int64,2}:
 1  2
 3  4)

This would become

Nullable{Array{Int64,2}(2x2 Array{Int64,2}

@davidagold
Copy link
Contributor

@eschnett True. Perhaps the solution would be only to print a Nullable's eltype if the latter is a bits type.

In general this discussion seems to reflect tensions in the intended use of the Nullable. If Nullables represent, say, (un)observed data, then it makes sense to make the presence of the wrapping container as invisible as possible. This is reflected in the show methods for NullableArrays, which were developed with statistical functionality in mind. In more general settings, it probably makes the most sense to print the eltype, modulo redundancy. If, in the future, different "distributions" of Julia are shipped for different uses, then perhaps the statistics/data analysis distribution will contain either a package or command line argument to activate abbreviated show methods for Nullables.

@eschnett
Copy link
Contributor

eschnett commented Dec 7, 2015

@davidagold I think the distinction runs between immutable and mutable containers. If a container can be modified, then it's important to know its abstract element type. However, if a container is immutable and holds at most a single element, then it's less important to know the abstract element type -- a particular container object will only ever hold the value at hand, which has a concrete type.

@davidagold
Copy link
Contributor

@eschnett That's also a good point. Do you think this constitutes a significant enough disanalogy between Arrays and Nullables so that the show conventions might plausibly differ between the two? And are there any other immutable containers in Base?

@toivoh
Copy link
Contributor

toivoh commented Dec 7, 2015

Another point is that I'd like to know if I'm getting eg a Nullable{Any}(1). That can happen, right?

@eschnett
Copy link
Contributor

eschnett commented Dec 7, 2015

@davidagold Yes, I think so. No, I don't know about any other immutable containers.

@MikeInnes
Copy link
Member

Perhaps just don't print leaf types, but do print abstract ones?

@davidagold
Copy link
Contributor

Given @eschnett 's observation, is it reasonable to ask whether or not non-empty Nullable objects should even be allowed abstract type parameters? We currently have

julia> x = Nullable{Integer}(1)
Nullable(1)

julia> isa(x, Nullable{Int})
false

julia> typeof(get(x))
Int64

i.e. that the type parameter for a non-empty Nullable object is not completely determined by whatever value it wraps. Is this weird for an immutable container that contains at most one value?

Relatedly, what does the compiler see/do when it encounters a non-empty Nullable{Integer} during type inference? Is it less efficient that what is possible upon encountering a non-empty Nullable{Int}?

EDIT: I suppose one very good reason to have abstract type parameters for nonempty Nullables is so that you can have, e.g. Array{Nullable{Integer}, 1} contain, say, both Nullable{Integer}(Int64(1)) and Nullable{Integer}(Int32(1)).

@toivoh
Copy link
Contributor

toivoh commented Dec 9, 2015

A concrete type parameter like in Nullable{Int} should of course be the best for type inference. But it might be better to be able to infer Nullable{Integer} than Union{Nullable{Int32}, Nullable{Int64}} (and definitely better than Any if type inference gave up).

@johnmyleswhite
Copy link
Member

Printing the type parameter seems like a good idea to me given how verbose things already are.

@bicycle1885
Copy link
Member Author

I think it is okay to be a little bit verbose for the show method. According to #14052, show is used to show the structure of an object while print is used to show only the value.

If we regard a Nullable object as a simple value, it may be reasonable to print only the value wrapped by Nullable when we call print. For example:

function show{T}(io::IO, x::Nullable{T})
    print(io, "Nullable{", T, "}(")
    if !isnull(x)
        show(io, x.value)
    end
    print(io, ')')
end

function print(io::IO, x::Nullable)
    if isnull(x)
        print(io, "null")
    else
        print(io, get(x))
    end
end

@ScottPJones
Copy link
Contributor

That seems like a good distinction, @bicycle1885. 👍

@hayd
Copy link
Member

hayd commented Dec 15, 2015

It seems to me that Array{Nullable{Integer}, 1} is rather an edge case (where we don't distinguish in show different values which show the same even thought they have a different value). We don't in Array:

julia> Integer[Int64(1), Int32(2)]
2-element Array{Integer,1}:
 1
 2

That said, IMO if it's a non-concrete type the full type should be shown. BUT that's a different issue to this one about Nullable.


I wonder if, since Nullable Array is a frequent case, we should optimize the output / make it less verbose:

julia> Nullable{Int64}[Nullable(1) Nullable(2); Nullable(3) Nullable()]
2x2 Array{Nullable{Int64},2}:
 Nullable{Int64}(1)  Nullable{Int64}(2)
 Nullable{Int64}(3)  Nullable{Int64}()

should be

julia> Nullable{Int64}[Nullable(1) Nullable(2); Nullable(3) Nullable()]
2x2 Array{Nullable{Int64},2}:
 1  2
 3  _

or similar.

@jakebolewski
Copy link
Member

Going with @johnmyleswhite comment, I don't think the added complexity of coming up with a heuristic or rule when the printing type parameter information is redundant or not is worth it.

jakebolewski added a commit that referenced this pull request Dec 16, 2015
print the type parameter of Nullable
@jakebolewski jakebolewski merged commit afcbab1 into JuliaLang:master Dec 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.