Structs calling each other

I would like to define two structs AB and BA and be able to convert from one representation to the other doing AB(ba) or BA(ab) where ab and ba are instances of AB and BA respectively.

for example :

mutable struct AB
    a::Int
    b::Int
    function AB(a::Int, b::Int)
        new(a, b)
    end
    function AB(ba::BA) # convert from BA
        new(ba.b, ba.a)
    end
end

mutable struct BA
    a::Int
    b::Int
    function BA(ab::AB) # convert from AB
        new(ab.b, ab.a)
    end
end

But I cannot do that because BA is not yet defined when AB is being defined.
Can I just add a function outside of the structs that does

function AB(ba::BA)
    return AB(ba.b, ba.a)
end

?
Then is it a problem that AB is both a type and a function ?

Functions like that are fine, when you use constructors inside struct definitions they have the special ability to define the actual struct with new(...) which is the “actual” constructor and will not dispatch to any other thing. So inner constructors can be nice as a guard to disallow construction of a struct without some conditions on the fields being met. You cannot do that as well with outer constructors because you have to call the inner constructor in them, so at that point your checks might not hold anymore.

https://docs.julialang.org/en/v1/manual/constructors/

1 Like

To be clear, if you moved your “converting” constructors outside of the struct block (and replaced new with a call to a constructor) so that they became normal functions, you’d get what you want.

E.g.,

AB(ba::BA) = AB(ba.a, ba.b)
BA(ab::AB) = BA(ab.b, ab.a)

Also, your inner constructor

    function AB(a::Int, b::Int)
        new(a, b)
    end

is basically a duplicate of the default constructor except that it’s less flexible (defining any inner constructor prevents a default constructor from being defined). I would delete it. Inner constructors (functions defined inside a struct block) are only needed in some special cases. For example, you could use an inner constructor to require that any constructed instance satisfies a < b.

3 Likes