> Here is a fun challenge for anyone who thinks "it can't be that bad": Try to implement a TwoWayDict, an AbstractDict where if d[a] = b, then d[b] = a
I've done the exercise, let me walk you through it.
First, there is no inheritance of concrete types, only composition, so I wrote a wrapper:
struct TwoWayDict{K, V, D <: AbstractDict{K,V}} <: AbstractDict{K,V}
d::D
end
import Base: setindex!
function setindex!(d, key, value)
d.d[value] = key
d.d[key] = value
end
julia> d["a"] = "b"
"b"
julia> d
Error showing value of type TwoWayDict{String, String, Dict{String, String}}:
ERROR: MethodError: no method matching length(::TwoWayDict{String, String, Dict{String, String}})
Hm, so length is missing, let's add that
julia> import Base: length
julia> length(x::TwoWayDict) = length(x.d)
julia> d
TwoWayDict{String, String, Dict{String, String}} with 2 entries:
"b" => "a"
"a" => "b"
It should be documented better, but without leaving the repl it's not that difficult to implement the basics, just some function forwarding really.
Now if you ask: did you implement the full interface? I don't know [1], but I do like that julia doesn't force me to implement things I don't need in my code. By not being strict about interfaces, julia solves the expression problem [2], and in some cases this is very useful. E.g. if I want to create a number type and I only want to implement +, -, *, /, and potentially conversion and promotion, then I can do that, but I don't have to worry about exponentiation, trig functions, or whatever people think is encapsulated by the notion of number.
[1] Well, I forgot to write a constructor to enforce the d[a] = b and d[b] = a invariant on instantiation, and there's no support for deletion by key.
This is one of those comments that’s so instructive I’m going to save it, because I’ll probably want to refer to it in the future. Thanks for taking the trouble.
I've done the exercise, let me walk you through it.
First, there is no inheritance of concrete types, only composition, so I wrote a wrapper:
How do I know this signature? By looking at and the {K, V, D <: AbstractDict{K,V}} pattern is a well-known trick in julia.Then I tried to instantiate a TwoWayDict in the REPL, and it complains about iteration support, so I implement that:
How about setting a value? Okay, so let's implement that Hm, so length is missing, let's add that Ok great. How about retrieving a value: Hm, okay, 3 arguments?! Let's see how it works for Dict: Ok so ---It should be documented better, but without leaving the repl it's not that difficult to implement the basics, just some function forwarding really.
Now if you ask: did you implement the full interface? I don't know [1], but I do like that julia doesn't force me to implement things I don't need in my code. By not being strict about interfaces, julia solves the expression problem [2], and in some cases this is very useful. E.g. if I want to create a number type and I only want to implement +, -, *, /, and potentially conversion and promotion, then I can do that, but I don't have to worry about exponentiation, trig functions, or whatever people think is encapsulated by the notion of number.
[1] Well, I forgot to write a constructor to enforce the d[a] = b and d[b] = a invariant on instantiation, and there's no support for deletion by key.
[2] https://en.wikipedia.org/wiki/Expression_problem