Making a type of AbstractDict

I am trying to create a fixed dictionary with builtin restore to a default state:

module BackedUpImmutable

export BackedUpImmutableDict, getindex, setindex!, get!, get, restore!

struct BackedUpImmutableDict{K, V} <: AbstractDict{K,V}
    d::Base.ImmutableDict{K, V}
    defaults::Dict{K, V}
end

function BackedUpImmutableDict{K,V}(pairs::Vector{Pair{K,V}}) where V where K
    id = Base.ImmutableDict(pairs[1][1] => pairs[1][2])
    for p in pairs[2:end]
        id = Base.ImmutableDict(id, p[1] => p[2])
    end
    BackedUpImmutableDict(id, Dict{K,V}(pairs...))
end

getindex(dic::BackedUpImmutableDict{K,V}, key::K) where V where K = dic.d[key]
setindex!(dic::BackedUpImmutableDict{K,V}, k::K, v::V) where V where K = setindex!(dic.d, k, v)

get(dic::BackedUpImmutableDict{K,V}, k::K, v::V) where V where K = get(dic.d, k, v)
get!(dic::BackedUpImmutableDict, k::K, v::V) where V where K = get!(dic.d, k, v)

function restore!(dic, k)
    if haskey(dic.defaults, k)
        dic.d[k] = (v = defaults[k])
        return v
    end
end

end

using .BackedUpImmutable

function testBackedUpImmutableDict()
    fibr = BackedUpImmutableDict{String,Int64}(["a" => 0, "b" => 1, "c" => 1, "d" => 2,
        "e" => 3, "f" => 5, "g" => 8, "h" => 13, "i" => 21, "j" => 34, "extra" => -1])

    x = fibr["extra"]
    fibr["extra"] = 0
    y = fibr["extra"]
    restore!(fibr, "extra")
    z = fibr["extra"]
    println("first $x, then $y, then back to $z")
    
    try
        fibr["k"] = 55
    catch
        println("throws ok for readonly")
    end

end

testBackedUpImmutableDict()

This compiles with the error:
ERROR: LoadError: MethodError: no method matching get(::BackedUpImmutableDict{String,Int64}, ::String, ::Symbol)

The problem is that I don’t know why it thinks I am defining a get() with a :Symbol type as the last argument?

import Base.getindex, Base.setindex!, Base.get, Base.get!, Base.length
length(dic::BackedUpImmutableDict{K,V}) where V where K = length(dic.d)

getindex(dic::BackedUpImmutableDict{K,V}, key::K) where V where K = dic.d[key]
setindex!(dic::BackedUpImmutableDict{K,V}, v::V, k::K) where V where K = setindex!(dic.d, v, k)

get(dic::BackedUpImmutableDict{K,V}, k::K, v::V) where K where V = get(dic.d, k, v)
get!(dic::BackedUpImmutableDict, k::K, v::V) where V where K = get!(dic.d, k, v)

I added length because the Juno debugger needs to get the length if you step through the code. There were two major issues, first you need to import the Base functions to correctly overload them. Second setindex! is value first then key.

https://docs.julialang.org/en/v1/base/collections/#Base.setindex!

HOWEVER this still doesn’t work, I believe it’s because setindex! is not implemented for an ImmutableDict, it being immutable and all, I’m betting you need to change:

    fibr["extra"] = 0

    fibr = BackedUpImmutableDict(fibr, "extra" => 0)

Which means you need to implement that constructor…