Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inherit from Ref in Julia

Tags:

julia

I've been learning Julia and wanted to spend some time trying it out by adding some of my favorite functional/immutable constructs to the language. Specifically: types for delayed computations and promises, like clojure's delay and promise types.

Both delays and promises are similar in principle to Ref{T} with the caveat that (1) obj[] may need to wait on a value or run a computation before returning when obj is a promise or delay and (2) a delay/promise can only be set once and never read prior to being set, so is immutable (at least, its interface is that of an immutable object).

My intuition here is that both delay and promise should inherit from an abstract immutable ref type, since this part of their behavior at least is similar; however, I can't seem to do this:

abstract type ImmutableRef <: Ref end

invalid subtyping in definition of ImmutableRef

After looking through the Julia source code a bit, it seems like the Ref type is not declared in a typical fashion and instead is declared in Julia's core C code. Is it possible to inherit from Ref in Julia? If not, what would be the idiomatic Julia way to implement/organize these kinds of ref-like types?

like image 399
nben Avatar asked Sep 23 '19 21:09

nben


1 Answers

As noted by Lyndon, the problem was that you didn't write Ref{T} in the type signature.

For fun, here's my implementation a promise type, though I'm sure there's a more elegant way that's makes more effort to pretend to be immutable.

struct Promise{T} <: Ref{T} 
    r::Ref{T}
    fufilled::Ref{Bool}
end
Promise{T}() where {T} = Promise{T}(Ref{T}(), Ref(false))
Promise() where {T}    = Promise{Any}(Ref{T}(), Ref(false))

function Base.getindex(p::Promise) 
    @assert p.fufilled[] == true
    p.r[]
end

function deliver(p::Promise{T}, val::U) where {U <: T}
    p.r[] = val; p.fufilled[] = true
    p
end

isrealized(p) = p.fufilled[]

Now if we go the repl and, we can check how this acts:

julia> x = Promise(); # If we know we'll deliver an Int then we should do Promise{Int}()

julia> isrealized(x)
false

julia> deliver(x, 1);

julia> x[]
1

Delay should be quite similar.

like image 80
Mason Avatar answered Nov 15 '22 06:11

Mason