# How do I correctly make an "interface" in Julia?

**URL:** <https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676>\
**Category:** General Usage\
**Created:** [June 15, 2024, 1:08am UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676 "2024-06-15T01:08:09Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![vshesh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vshesh/32/20362_2.png) [@vshesh](https://discourse.julialang.org/u/vshesh)\
**Post date:** [June 15, 2024, 1:08am UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/1 "2024-06-15T01:08:09Z")

</div>

With multiple dispatch I am able to specialize any function already written to a type, but when it comes time to define my own “interfaces” (although here they are just generic functions) I get a bit confused.

I want to translate this idea to Julia:

```julia
Nestable<B, L> {
   branch(n:Nestable<B, L>): Nestable<B, L>[]
   construct(value: B, branches: Nestable<B, L>[]): Nestable<B, L>[]
   attach(n:Nestable<B,L>, branches: Nestable<B,L>[]): Nestable<B,L>[]
   value(n:Nestable<B, L>): B
   isLeaf(n:L | Nestable<B,L>): n is L
}

```

This type defines a generic set of functions that work with anything that can be nested.  
The naive approach gives me:

```julia
# i'm not sure what value this has when I can't use the type params
function isleaf(n::Any)::Bool end 
function value(n::Any)::Any end 
function attach(n::T, branches::T)::T where T end 
function construct(value::Any, branches::T)::T where T end
# AbstractArray might even be too specific, Set, Map etc are all fine. Any iterable will do.
function branch(n::T)::AbstractArray{T} end

```

I tried to look for a `Iterable<T>` idea in Julia to get some inspiration but noticed that instead Julia chooses to use functions to define behavior, not types. This is cool and seems powerful but I’m not sure how to apply it to my use case.

Any thoughts? Here’s one of the `Nestable` related functions I’m trying to port over:

```julia
typescript
// this is a concrete example implementation for arrays but i would want to be more general
export type Branch<B, L> = [B, ...(L | Branch<B, L>)[]]
// Ideally I'd be able to say Tree<Branch<B, L>> = L | Branch<B, L>
export type Tree<B, L> = L | Branch<B, L>
export type Forest<B, L> = Tree<B, L>[]

/**
Very generic tree transform. 
Takes 3 functions and a branch and 
returns a new branch where the values are mapped, 
the leaves are transformed, and the nodes themselves are also transformed. 

By default branches generated by transforming leaves are transformed by `n`. 
If you don't want this, then pass `false` for the `deep` parameter. 
*/
function transform<B, L, B2, L2>(
    l: (t: L) => Tree<B2, L2>[], 
    b: (b: B) => B2,
    n: (t: Branch<B2, L2>) => Forest<B2, L2>[],
    tree: Branch<B, L>,
    deep: boolean = true): Branch<B2, L2> {  
  return construct(b(value(tree)), branch(tree) |> R.chain(
    (x: Tree<B, L>) => isLeaf(x) 
      ? l(x) |> (deep ? R.chain((y: Tree<B2, L2>) => isLeaf(y) ? [y] : n(y)) : identity)
      : n(transform(l, b, n, x)) 
  ));
}

// identity = x -> x 
// chain composes functions together

```

---

<div class="post-metadata">

**Author:** ![Satvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/satvik/32/20486_2.png) [@Satvik](https://discourse.julialang.org/u/Satvik)\
**Post date:** [June 15, 2024, 2:40am UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/2 "2024-06-15T02:40:56Z")

</div>

Julia doesn’t have a formal concept of interfaces (yet?). My understanding is that most people agree it would be useful but finding an implementation that works is difficult.

All you can currently do is use informal interfaces, writing code that only uses functions on structs rather than their properties. For example, the informal dict interface has 9 functions like `getindex`, `setindex`, `haskey` etc. Almost all dict-related code uses these functions, rather than any internals of a dict, by convention. So you can implement your own type with all these functions and expect it to work anywhere a dict works – see e.g. ThreadSafeDicts.jl

So you couldn’t really build functions that work on anything Nestable. Instead, you could implement the functions `isleaf`, `value`, etc. on various types, and then you’d have an informal “Nestable” interface. You could define functions like `transform` that worked on any type for which you had implemented the Nestable interface.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [June 15, 2024, 5:20am UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/3 "2024-06-15T05:20:48Z")

</div>

> [@Satvik](#):
>
> All you can currently do is use informal interfaces

That’s not entirely true. While the language itself doesn’t have built-in interfaces, there are several third-party packages that propose designs for this feature.

- Interfaces.jl
- RequiredInterfaces.jl
- [DuckDispatch.jl](https://github.com/mrufsvold/DuckDispatch.jl)

See also this discussion:

> [@\[RFC/WIP\] DuckDispatch.jl](https://discourse.julialang.org/t/rfc-wip-duckdispatch-jl/114930/):
>
> I’ve been working through an idea for a package, and I’d love your feedback. Tl;Dr: This package allows you to create method dispatches based on the methods defined for a type, not the place the type has in the type lattice. Here’s a little snippet to get the idea: @duck\_type struct FiniteIterable{T} # the signatures that must be defined to make a type a `FiniteIterable` function Base.iterate(::This)::Union{Nothing, Tuple{T, \<:Any}} end function Base.iterate(::This, ::Any)::Uni…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 15, 2024, 8:38am UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/4 "2024-06-15T08:38:28Z")

</div>

Here the correct link: [GitHub - mrufsvold/DuckDispatch.jl: If it quacks like a duck... dispatch on it!](https://github.com/mrufsvold/DuckDispatch.jl)

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [June 15, 2024, 12:07pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/5 "2024-06-15T12:07:38Z")

</div>

I tried to implement this using DuckDispatch.jl, and this definition introduces a number of very complex nuances that I’ve thought about but haven’t had time to implement.

Namely:

1. Dispatching on two interfaces (`Nestable` and `Iterable{Nestable}`)
2. Dispatching a method where the `DuckType` is not a top-level type for any argument – `construct(::B, Iterable{Nestable})`.
3. Annotating the return type of a method as being a `DuckType`.

None of these are intractable, but they are delicate and require some internals black magic.

Anyway, at this time, `DuckDispatch` can’t help you with this intricate of an Interface declaration, but hopefully, it will soon!

---

<div class="post-metadata">

**Author:** ![vshesh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vshesh/32/20362_2.png) [@vshesh](https://discourse.julialang.org/u/vshesh)\
**Post date:** [June 15, 2024, 4:45pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/6 "2024-06-15T16:45:42Z")

</div>

Thank you all for the help.

I like the multiple dispatch approach… interfaces are clunky because you have to introduce extra names and stick to the types that are defined and define either everything or nothing. This feels like the “limit” of interfaces which is great.

One more snag I ran into is that I cannot define recursive types in Julia. I can define recursive structs, but that’s it. So I can’t write `ArrayBranch{B, L} = Vector{Union{L, ArrayBranch{B, L}}}`. Ragged arrays are one main type of tree I’m trying to process - how best can I express this?

I tried to get a simpler Rose Tree working and ran into some issues there too:

```julia
abstract type Branch{V, L} end 
Tree{B} = Union{L, B} where {V, L, B <: Branch{V, L}}
Forest{B} = Union{
  <: AbstractVector{Tree{B}}} where {V, L, B <: Branch{V, L}}

# Trying to make this work with Branch type
function isleaf(n::B)::Bool where {V,L, B <: Branch{V, L}} end 
function value(n::B)::V where{V, L, B <: Branch{V,L}} end 
function attach(n::B, branches::Forest{B})::B where {V, L, B <: Branch{V, L}} end 
function construct(value::V, branches::Forest{B})::B where {V, L, B <: Branch{V, L}} end
function branch(n::B)::Forest{B} where {V, L, B <: Branch{V, L}} end

abstract type RoseBranch{V, L} <: Branch{V, L} end 
TupleRoseBranch{V, L} = Tuple{V, Forest{<: RoseBranch{V, L}}}

```

But sadly

```julia
julia> isa((1, [2]), TupleRoseBranch{Int, Int})
false #oops, should be true

```

When I did some inspection I got

```julia
julia> Forest{RoseBranch{Int, Int}}
AbstractVector{<:Union{L, B1} where {L, B1<:Branch{B, L}}} 
                              where {L, B<:Branch{RoseBranch{Int64, Int64}, L}} 
(alias for AbstractArray{<:Union{L, B1} where {L, B1<:Branch{B, L}}, 1} where {L, B<:Branch{RoseBranch{Int64, Int64}, L}})

```

For some reason Julia is assigning `RoseBranch` to `V` instead of `B` and forcing `B1` to be `<: Branch{B< L}` instead of `<: RoseBranch{B, L}`

This is also not working:

```julia
julia> Tree{RoseBranch{Int, Int}}
Union{L, B} where {L, B<:Branch{RoseBranch{Int64, Int64}, L}}

```

Any ideas how to fix this?

---

<div class="post-metadata">

**Author:** ![vshesh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vshesh/32/20362_2.png) [@vshesh](https://discourse.julialang.org/u/vshesh)\
**Post date:** [June 15, 2024, 5:46pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/7 "2024-06-15T17:46:06Z")

</div>

Even this basic example I’m not able to get working:

```julia
julia> abstract type RoseBranch{V, L} end
julia> TupleRoseBranch{V, L} = Tuple{V, Vector{Union{<: RoseBranch{V, L}, L}}}
Tuple{V, Array{Union{RoseBranch{V, L}, L}, 1}} where {V, L}

julia> isa((1, [2]), TupleRoseBranch{Int, Int})
false

```

And neither did this:

```julia

julia> struct RoseBranchS{V, L} <: RoseBranch{V, L}
         v::V
         branches::Vector{Union{<: RoseBranch{V, L}, L}}
         end

julia> RoseBranch
RoseBranch

julia> RoseBranchS{Int, Int}
RoseBranchS{Int64, Int64}

julia> RoseBranchS{Int, Int}(120, [123])
RoseBranchS{Int64, Int64}(120, Union{Int64, RoseBranch{Int64, Int64}}[123])

julia> RoseBranchS{Int, Int}(120, [123, RoseBranchS(120, [])])
ERROR: MethodError: Cannot `convert` an object of type
  RoseBranchS{Int64, Any} to an object of type
  Union{Int64, RoseBranch{Int64, Int64}}

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 15, 2024, 6:09pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/8 "2024-06-15T18:09:47Z")

</div>

Could you specify your desired data structures? Some examples could also help, I guess.

> [@vshesh](#):
>
> Ragged arrays are one main type of tree I’m trying to process - how best can I express this?

A Web search leaves me confused. Apparently a ragged array is just an array of arrays. So why are you calling it a tree? Can you help me understand the requirements so I could help you implement this?

> [@vshesh](#):
>
> a simpler Rose Tree

Looking at the Wikipedia page, I’m again confused. Why is this called a tree? Does it actually represent a tree in the graph theoretic sense? The Wikipedia page presents some graphs that are not trees.

---

<div class="post-metadata">

**Author:** ![Satvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/satvik/32/20486_2.png) [@Satvik](https://discourse.julialang.org/u/Satvik)\
**Post date:** [June 15, 2024, 6:26pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/9 "2024-06-15T18:26:03Z")

</div>

> Blockquote  
> julia\> abstract type RoseBranch{V, L} end  
> julia\> TupleRoseBranch{V, L} = Tuple{V, Vector{Union{\<: RoseBranch{V, L}, L}}}  
> Tuple{V, Array{Union{RoseBranch{V, L}, L}, 1}} where {V, L}

In this example you need `TupleRoseBranch{V, L} = Tuple{V, Vector{<:Union{<: RoseBranch{V, L}, L}}}`. Because a `Vector{Union{Int, X}` is not a `Vector{Int}` – Julia’s collection types are invariant, rather than covariant or contravariant.

It’s harder to get the second example to work. This will work:

```julia
a = RoseBranchS(120, Int[])
julia> RoseBranchS{Int, Int}(121, [a])
RoseBranchS{Int64, Int64}(121, RoseBranchS{Int64, Int64}[RoseBranchS{Int64, Int64}(120, Int64[])])

```

But if we add an Int to the second argument, it no longer works:

```julia
julia> RoseBranchS{Int, Int}(121, [1, a])
ERROR: MethodError: no method matching (Vector{<:Union{Int64, var"#s3"} where var"#s3"<:RoseBranch{Int64, Int64}})(::Vector{Any})
Stacktrace:
 [1] convert(::Type{Vector{<:Union{Int64, var"#s3"} where var"#s3"<:RoseBranch{Int64, Int64}}}, a::Vector{Any})
   @ Base ./array.jl:665
 [2] RoseBranchS{Int64, Int64}(v::Int64, branches::Vector{Any})
   @ Main ./REPL[7]:2
 [3] top-level scope
   @ REPL[18]:1

```

Because `[1, a]` has type `Vector{Any}` – it doesn’t default to a union type  
I think you can make it work with `Vector{Union{Int, RoseBranchS{Int, Int}}}([1, a])` but that’s significantly clunkier. Given how challenging it is to get the vectors to have the right types, you might just want to define them as `Vector{Any}` – it’s unlikely that you’ll be dispatching on such specific vector types.

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [June 15, 2024, 7:26pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/10 "2024-06-15T19:26:05Z")

</div>

Such recursive types are probably not a sweet spot of Julia’s type system. On the other hand, Julia is dynamically typed and thus, you can get away with much less type information:

```julia
struct MyRose
   val
   branches
end

isleaf(node::MyRose) = isempty(node.branches)
value(node::MyRose) = node.val
branch(node::MyRose) = node.branches
attach(node::MyRose, branches::AbstractVector) = MyRose(value(node), vcat(branch(node), branches))
# Note: Such type based dispatch is often harder to get bullet-proof in dynamically typed languages
construct(val, branches::AbstractVector{<:MyRose}) = MyRose(val, branches)

```

Parametric types are available in Julia, but usually serve different purposes than in statically typed languages:

1. Information to the compiler to allow for specialized code, i.e., type stability  
For this, I usually just use

```julia
struct MyRose{V,F}
    val::V
    branches::F
end

```

and let the compiler figure out whatever types are needed.
2. Dispatch on argument and element types – most often this does not require deeply nested, abstract types.

If data need to have certain type invariants an inner constructor with `@assert` can be used. In the end, there are no compile-time type errors anyways.

PS: For inspiration on how an interface for trees might look like in Julia, you may want to check [AbstractTrees.jl](https://github.com/JuliaCollections/AbstractTrees.jl)

---

<div class="post-metadata">

**Author:** ![vshesh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vshesh/32/20362_2.png) [@vshesh](https://discourse.julialang.org/u/vshesh)\
**Post date:** [June 16, 2024, 9:27pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/11 "2024-06-16T21:27:24Z")

</div>

Hi, thank you again for all the advice.  
I don’t know what it means for something to be a tree from a “graph theoretic principle” per se but I am working on a project where there are a lot of trees in various formats, such as:

- structs (like basic tree node from C++ or something)
- ‘ragged array’ (maybe the wrong name, I meant something like: [GitHub - weavejester/hiccup: Fast library for rendering HTML in Clojure](https://github.com/weavejester/hiccup))
- file system (which is also a tree)
- tuples (think (tag, attrs, children) or named tuple like format. the last position will hold the children and the rest will have data)

So I want to abstract away the traversals (so I don’t write lots of subtly different ones) and be able to absorb all of those structures and use them. Hence the interface approach.

I looked at that library and I can see all the zero-entry structs being used - yeah that seems complicated. For now I will stick to using concrete implementations and worry about type hierarchies later.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [June 17, 2024, 11:43pm UTC](https://discourse.julialang.org/t/how-do-i-correctly-make-an-interface-in-julia/115676/12 "2024-06-17T23:43:04Z")

</div>

I would encourage you to look at Graphs.jl, specifically their API page. There you can see the minimal interface functions you need to define for a type to opt into the whole ecosystem’s Graph traversal, analysis, etc and tooling!
