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).
>

Reply via email to