JLD and package extensions

I would like to make a package extension that loads if JLD.jl is loaded. I got the code below to work in the REPL, but when I make Abc the main package and JLDExt the extension (and remove the dots in front of the package names) I get the warning “type JLDExt.JLDAb not present in workspace; reconstructing” and the deserialization fails.

module Abc

export Ab

struct Ab
    a
end

end # module Abc

#----------------------

module JLDExt

using ..Abc, JLD
import JLD.writeas
import JLD.readas

export JLDAb

struct JLDAb
    a
end

JLD.writeas(x::Ab) = writeas(JLDAb(x.a))
JLD.readas(x::JLDAb) = Ab(x.a)

end

#--------------------

using Test, .Abc, .JLDExt, JLD

@testset "JLD" begin
    x = Ab(1)
    fname = "/tmp/JLD_test.jld"
    save(fname, "x", x)
    @test load(fname)["x"] == x
end

The precise code with all the files involved is at GitHub - GHTaarn/Abc.jl: For a post on https://discourse.julialang.org

1 Like

I worked on this some more and it appears that new symbols defined in extensions are not normally visible from outside the extension. I have gotten things to work with an ugly solution at GitHub - GHTaarn/Abc.jl at fix_alpha that has the following Julia files:

module Abc

export Ab, JLDExt

struct Ab
    a
end

function set_jldext()
    global JLDExt
    pause = 0.01
    for t in 0:pause:2
        JLDExt = Base.get_extension(@__MODULE__, :JLDExt)
        !isnothing(JLDExt) && break
        sleep(pause)
    end
    @info "JLDExt set to '$JLDExt'"
end

end # module Abc
module JLDExt

using Abc, JLD
import JLD.writeas
import JLD.readas

struct JLDAb
    a
end

JLD.writeas(x::Ab) = writeas(JLDAb(x.a))
JLD.readas(x::JLDAb) = Ab(x.a)

function __init__()
    @async Abc.set_jldext()
    @info "Loaded JLDExt"
end

end
using Test, Abc, JLD

@testset "JLD" begin
    sleep(0.1)
    x = Ab(1)
    fname = "/tmp/JLD_test.jld"
    save(fname, "x", x)
    @test load(fname)["x"] == x
end

Any suggestions on how to avoid the sleeps would be appreciated. Is there a callback for when a module is loaded or something that wait can be called on that triggers when a module is loaded?

After a good nights sleep, I discovered that the solution is really simple:

module Abc

export Ab, JLDExt

struct Ab
    a
end

function set_jldext(m)
    global JLDExt = m
    @info "JLDExt set to '$JLDExt'"
end

end # module Abc
module JLDExt

using Abc, JLD
import JLD.writeas
import JLD.readas

struct JLDAb
    a
end

JLD.writeas(x::Ab) = writeas(JLDAb(x.a))
JLD.readas(x::JLDAb) = Ab(x.a)

function __init__()
    Abc.set_jldext(JLDExt)
    @info "Loaded JLDExt"
end

end
using Test, Abc, JLD

@testset "JLD" begin
    x = Ab(1)
    fname = "/tmp/JLD_test.jld"
    save(fname, "x", x)
    @test load(fname)["x"] == x
end

Full code available at GitHub - GHTaarn/Abc.jl at good_fix