Skip to content

Commit 892e746

Browse files
Add a parametric Nullable{T} type
1 parent dea5766 commit 892e746

File tree

7 files changed

+382
-6
lines changed

7 files changed

+382
-6
lines changed

base/exports.jl

+9-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export
6161
MathConst,
6262
Matrix,
6363
MergeSort,
64+
Nullable,
6465
ObjectIdDict,
6566
OrdinalRange,
6667
PollingFileWatcher,
@@ -145,6 +146,7 @@ export
145146
KeyError,
146147
LoadError,
147148
MethodError,
149+
NullException,
148150
ParseError,
149151
ProcessExitedException,
150152
SystemError,
@@ -197,7 +199,7 @@ export
197199
,
198200
!==,
199201
,
200-
,
202+
,
201203
$,
202204
%,
203205
&,
@@ -964,7 +966,7 @@ export
964966
rfft,
965967
xcorr,
966968

967-
# numerical integration
969+
# numerical integration
968970
quadgk,
969971

970972
# iteration
@@ -1010,7 +1012,7 @@ export
10101012
toc,
10111013
toq,
10121014

1013-
#dates
1015+
# dates
10141016
Date,
10151017
DateTime,
10161018
now,
@@ -1229,7 +1231,7 @@ export
12291231
# shared arrays
12301232
sdata,
12311233
indexpids,
1232-
1234+
12331235
# paths and file names
12341236
abspath,
12351237
basename,
@@ -1323,6 +1325,9 @@ export
13231325
unsafe_pointer_to_objref,
13241326
unsafe_store!,
13251327

1328+
# nullable types
1329+
isnull,
1330+
13261331
# Macros
13271332
@__FILE__,
13281333
@b_str,

base/nullable.jl

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
immutable Nullable{T}
2+
isnull::Bool
3+
value::T
4+
5+
Nullable() = new(true)
6+
Nullable(value::T) = new(false, value)
7+
end
8+
9+
immutable NullException <: Exception
10+
end
11+
12+
Nullable{T}(value::T) = Nullable{T}(value)
13+
14+
function convert{S, T}(::Type{Nullable{T}}, x::Nullable{S})
15+
return isnull(x) ? Nullable{T}() : Nullable(convert(T, get(x)))
16+
end
17+
18+
function show{T}(io::IO, x::Nullable{T})
19+
if x.isnull
20+
@printf(io, "Nullable{%s}()", repr(T))
21+
else
22+
@printf(io, "Nullable(%s)", repr(x.value))
23+
end
24+
end
25+
26+
get(x::Nullable) = x.isnull ? throw(NullException()) : x.value
27+
28+
get{S, T}(x::Nullable{S}, y::T) = x.isnull ? convert(S, y) : x.value
29+
30+
isnull(x::Nullable) = x.isnull
31+
32+
function isequal{S, T}(x::Nullable{S}, y::Nullable{T})
33+
if x.isnull && y.isnull
34+
return true
35+
elseif x.isnull || y.isnull
36+
return false
37+
else
38+
return isequal(x.value, y.value)
39+
end
40+
end
41+
42+
=={S, T}(x::Nullable{S}, y::Nullable{T}) = throw(NullException())
43+
44+
function hash(x::Nullable, h::Uint)
45+
if x.isnull
46+
return h + uint(0x932e0143e51d0171)
47+
else
48+
return hash(x.value, h + uint(0x932e0143e51d0171))
49+
end
50+
end

base/sysimg.jl

+3
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ importall .Profile
270270
include("Dates.jl")
271271
import .Dates: Date, DateTime, now
272272

273+
# nullable types
274+
include("nullable.jl")
275+
273276
function __init__()
274277
# Base library init
275278
reinit_stdio()

doc/manual/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
linear-algebra
2929
networking-and-streams
3030
parallel-computing
31+
nullable-types
3132
interacting-with-julia
3233
running-external-programs
3334
calling-c-and-fortran-code

doc/manual/nullable-types.rst

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
.. _man-nullable-types:
2+
3+
*******************************************
4+
Nullable Types: Representing Missing Values
5+
*******************************************
6+
7+
In many settings, you need to interact with a value of type ``T`` that may or
8+
may not exist. To handle these settings, Julia provides a parametric type
9+
called ``Nullable{T}``, which can be thought of as a specialized container
10+
type that can contain either zero or one values. ``Nullable{T}`` provides a
11+
minimal interface designed to ensure that interactions with missing values
12+
are safe. At present, the interface consists of four possible interactions:
13+
14+
- Construct a ``Nullable`` object.
15+
- Check if an ``Nullable`` object has a missing value.
16+
- Access the value of a ``Nullable`` object with a guarantee that a
17+
``NullException`` will be thrown if the object's value is missing.
18+
- Access the value of a ``Nullable`` object with a guarantee that a default
19+
value of type ``T`` will be returned if the object's value is missing.
20+
21+
Constructing ``Nullable`` objects
22+
---------------------------------
23+
24+
To construct an object representing a missing value of type ``T``, use the
25+
``Nullable{T}()`` function:
26+
27+
.. doctest::
28+
29+
x1 = Nullable{Int}()
30+
x2 = Nullable{Float64}()
31+
x3 = Nullable{Vector{Int}}()
32+
33+
To construct an object representing a non-missing value of type ``T``, use the
34+
``Nullable(x::T)`` function:
35+
36+
.. doctest::
37+
38+
x1 = Nullable(1)
39+
x2 = Nullable(1.0)
40+
x3 = Nullable([1, 2, 3])
41+
42+
Note the core distinction between these two ways of constructing a ``Nullable``
43+
object: in one style, you provide a type, ``T``, as a function parameter; in
44+
the other style, you provide a single value of type ``T`` as an argument.
45+
46+
Checking if an ``Nullable`` object has a value
47+
----------------------------------------------
48+
49+
You can check if a ``Nullable`` object has any value using the ``isnull``
50+
function:
51+
52+
.. doctest::
53+
54+
isnull(Nullable{Float64}())
55+
isnull(Nullable(0.0))
56+
57+
Safely accessing the value of an ``Nullable`` object
58+
----------------------------------------------------
59+
60+
You can safely access the value of an ``Nullable`` object using the ``get``
61+
function:
62+
63+
.. doctest::
64+
65+
get(Nullable{Float64}())
66+
get(Nullable(1.0))
67+
68+
If the value is not present, as it would be for ``Nullable{Float64}``, a
69+
``NullException`` error will be thrown. The error-throwing nature of the
70+
``get`` function ensures that any attempt to access a missing value immediately
71+
fails.
72+
73+
In cases for which a reasonable default value exists that could be used
74+
when a ``Nullable`` object's value turns out to be missing, you can provide this
75+
default value as a second argument to ``get``:
76+
77+
.. doctest::
78+
79+
get(Nullable{Float64}(), 0)
80+
get(Nullable(1.0), 0)
81+
82+
Note that this default value will automatically be converted to the type of
83+
the ``Nullable`` object that you attempt to access using the ``get`` function.
84+
For example, in the code shown above the value ``0`` would be automatically
85+
converted to a ``Float64`` value before being returned. The presence of default
86+
replacement values makes it easy to use the ``get`` function to write
87+
type-stable code that interacts with sources of potentially missing values.

0 commit comments

Comments
 (0)