Nullable is Julia's closest equivalent to Haskell's Maybe. But there are important differences:
* Presently run-time dispatch through even a very restricted subset of types is quite costly. So you want to make sure that all code allows type inference to assign a concrete type to every value. Nullable allows this, whereas any Union(S, T) with S != T will not. We dealt with the resulting performance problem for years in DataArrays; Nullable is the solution to that problem. * Julia does literally nothing to ensure compile-time exhaustiveness (cf. https://blogs.janestreet.com/what-do-haskellers-have-against-exhaustiveness/), which means that Nullable's sole value is providing a concrete type that encodes (a) all values in a set S and (b) the lack of a value from S. Put another way: branching on nullness should always happen in run-time world via the isnull() predicate. Nullable is not meant to allow dispatching on nullness. For anyone interested in having more background on this topic, you might check out my talk at last year's JuliaCon. We literally invented Nullable during that talk; our current implementation is very similar to the draft Stefan wrote while I was talking. -- John On Friday, May 29, 2015 at 12:20:32 PM UTC-7, andrew cooke wrote: > > On Friday, 29 May 2015 15:58:12 UTC-3, Yichao Yu wrote: >> >> On Fri, May 29, 2015 at 2:12 PM, andrew cooke <[email protected]> wrote: >> > then Julia needs a Maybe type as well? >> >> Note that different from `Nullable{T}`, which is a type by itself, >> `Maybe{T}` as proposed in the issue and you email, is just a type >> alias. In this sense, it is already defined (just write >> `Union(Nothing, ...)`) and it can already appear in type inference. >> >> ``` >> julia> f(a) = a > 0 ? nothing : 1 >> f (generic function with 1 method) >> >> julia> @code_typed f(1) >> 1-element Array{Any,1}: >> :($(Expr(:lambda, Any[:a], >> Any[Any[],Any[Any[:a,Int64,0]],Any[],Any[]], :(begin # none, line 1: >> unless (top(slt_int))(0,a::Int64)::Bool goto 0 >> return nothing >> 0: >> return 1 >> end::Union(Int64,Void))))) >> ``` >> >> It might make sense to add such a type alias if a lot of people need >> to write it but I personally don't think that's the case. >> >> First of all, if the function returns a certain concrete type or >> nothing, the type inference can figure that out by itself (as shown >> above) and you don't need to tell it anything about that. >> >> Second, you probably don't want to write that as the type constraint >> of the argument either. If the function doesn't have any other >> methods, writing that is meaningless (except as sanity check probably) >> since julia will specialize on the concrete type anyway. If the >> function has other methods, you will introduce ambiguity. >> >> ```julia >> julia> f(::Union(Int, Void)) = 1 >> f (generic function with 1 method) >> >> julia> f(::Union(Float64, Void)) = 2 >> Warning: New definition >> f(Union(Float64, Void)) at none:1 >> is ambiguous with: >> f(Union(Int64, Void)) at none:1. >> To fix, define >> f(Void) >> before the new definition. >> f (generic function with 2 methods) >> ``` >> >> For your usecase, according to what you've described, I don't think >> you will need to explicitly writh `Union(Nothing, ...)` >> >> 1. If you want to dispatch on a single Nothing and if the input has >> arbitrary types, just check for nothing explicitly or defining >> `f(::Nothing)` >> 2. If you want to distinguish between different types of Nothing (i.e. >> if the input is a missing Int or a missing Float64), you can probably >> use `Nullable{T}()` as the returned missing value. Whether you want to >> return Nullable or not for non-missing value depends on whether you >> want the user function (that generates the input value) to be type >> stable. >> > > 1 doesn't work because the user may have "meant to return the value > Nothing". that's why you need a type. because you need to go to a > metalanguage to describe having no value in the lower level language (aka > use / mention ditinction). i don't share your worry with type stability > yet because i have no idea if i can even do what i want - whether it is > fast or not comes much later. but i do want the user to be able to return > "anything" or "decide not to return anything at all", and since "anything" > can be literally Nothing, i cannot use a type union. > > so there seems to be a (3) which is unconnected with type stability, but > allows quoting. this is the kind of Maybe that haskell has (and what i was > thinking of when i suggested that Julia needed one). but since it is > structurally equivalent to Nullable then it seems like Nullable would do > just fine there. > > > >> > >> > On Friday, 29 May 2015 10:16:40 UTC-3, andrew cooke wrote: >> >> >> >> >> >> I'm not sure if I'm confused, or if there's a problem here, and I >> don't >> >> know what any fix would be anyway, so apologies for the open-ended >> post >> >> but... >> >> >> >> I cannot find on "option" type in Julia that I can dispatch on, so >> that I >> >> have a method call different functions, depending on whether a value >> is >> >> present or not. >> >> >> >> What I think I need is: >> >> >> >> typealias Maybe{T} Union(T,Nothing} >> >> >> >> >> >> >> >> That allows me to do: >> >> >> >> julia> foo(::Int) = "int" >> >> foo (generic function with 1 method >> >> >> >> julia> foo(::Nothing) = "nothing" >> >> foo (generic function with 2 methods) >> >> >> >> julia> bar(x::Maybe{Int}) = foo(x) >> >> bar (generic function with 1 method) >> >> >> >> julia> foo(1) >> >> "int" >> >> >> >> julia> foo(nothing) >> >> "nothing" >> >> >> >> julia> bar(nothing) >> >> "nothing" >> >> >> >> julia> bar(1) >> >> "int" >> >> >> >> >> >> which seems like what I want. >> >> >> >> HOWEVER, there's also Nullable, described at >> >> >> http://julia.readthedocs.org/en/latest/manual/types/#nullable-types-representing-missing-values >> >> >> and also at >> >> >> http://docs.julialang.org/en/latest/manual/faq/#nothingness-and-missing-values >> >> >> which seems like what I "should" be using. But I can't see how to >> dispatch >> >> on it. >> >> >> >> So it seems like one of the following is true >> >> >> >> 1 - There is a way to dispatch on Nothing, and please someone explain >> it >> >> to me >> >> >> >> 2 - Nullable should be changed so that it can be dispatched on >> >> >> >> 3 - We need Maybe in Base as well as Nothing. >> >> >> >> 1 or 2 sounds fine (although I personally don't see how you can do 2). >> 3 >> >> seems like the worst option, but still is presumably better than >> everyone >> >> and their dog defining this type in their own code. >> >> >> >> Any enlightenment appreciated, >> >> Andrew >> >> >> >> PS More references >> >> >> >> https://github.com/JuliaLang/julia/issues/3332 >> >> >> >> https://github.com/JuliaLang/julia/issues/1134 >> >> >> >> https://github.com/JuliaLang/julia/pull/8152 >> >
