I think many of the questions raised in this thread can be answered by
considering the history behind why Nullable{T} was introduced in the first
place; to replace NAtype and NA, from the DataArrays package. As such,
Nullable{T} is supposed to be used more as Milan describes, than as a
drop-in replacemet for Python's None - the idea is rather to have a wrapper
type for data that, if it is "missing" (which is what NA signalled)
"poisons" all calculations to return a missing value instead of the result.
Thus, equality with null should better be defined as
(==){T}(a::Nullable{T}, b::T) = !isnull(a) ? Nullable(get(a) == b) :
Nullable{Bool}()
This definition will be type-stable (it will always return a
Nullable{Bool}) and it will be able to signal all three possible results;
get(a) == b, get(a) != b and get(a) == null.
Now, for a sum function, it becomes a little less trivial: how do we treat
missing data? On one hand, we could argue that if all values are not known,
then the sum is not known either, and we should return null. On the other
hand, it might be more useful to return the sum of all non-null values.
Either way, we should make sure to do something that is type-stable. Naïve
implementations could look like
# if any nulls, return null:
function sum{T}(A::Array{Nullable{T,1}})
@inbounds for i = 1:length(A)
s = zero(T)
if isnull(A[i])
return Nullable{T}()
else
s += get(A[i])
end
end
return Nullable(s)
end
# just ignore null values:
function sum{T}(A::Array{Nullable{T,1}})
@inbounds for i = 1:length(A)
s = zero(T)
if !isnull(A[i])
s += get(A[i])
end
end
return Nullable(s)
end
If you take a look at the DataArrays package
(https://github.com/JuliaStats/DataArrays.jl) you'll find lots of examples
of functions like this for NA; you'll also notice that many of them are
*not* type stable, which - as stated above - is the original reason for
the Nullable{T} type in the first place.
// T
On Tuesday, January 6, 2015 2:32:07 PM UTC+1, Seth wrote:
>
>
> On Tuesday, January 6, 2015 4:43:16 AM UTC-8, Milan Bouchet-Valat wrote:
>>
>>
>> >
>> > Yeah, (==){T}(a::Nullable{T}, b::T) should be able to be defined as
>> > !isnull(a) && get(a) == b
>> I'd consider this definition (which is different from the ones I
>> suggested above) as unsafe: if `a` is `null`, then you silently get
>> `false`. Better provide additional safety by either returning a
>> `Nullable`, or raising an exception.
>>
>
> But - if "null" is just another legitimate value, why wouldn't it make
> sense to define "null != a" for all (a != null)? Why must we treat it as
> some sort of special abstraction? We don't do this with, say, imaginary
> numbers. (Identity for null is a separate issue).
>