Macro to inherit fields from one type to another

Hi, I am very new to Julia . Unsurprisingly, I was irritated by the fact that fields are not inherited from a base struct to the other. I clearly know such inheritance is not always desired,. But in some cases, it becomes quite useful, like when writing widgeting system (you dont want to declare posx, posy, width, height, children, onclick, ondragstart, and so on and so forth in every other widget you want)

Hence, I tried writing a macro to do the same. Please let me know if there are any issues. The usage is given later. The usage style could be a bit counterintuitive to some.

Please comment if the following looks good, or if there are any big gotchas. I also think this could be useful to others

#extendit.jl
macro inherit_fields(thetype)
    theRealType = eval(thetype)
    eArray = []
    for (thefieldname, thefieldtype) in zip(fieldnames(theRealType), fieldtypes(theRealType))
        push!(eArray, Expr(:(::), thefieldname, thefieldtype))
    end
    return esc(Expr(:block, eArray...))
end

How to use this :

#tryextending.jl
include("./extendit.jl")

struct A1
a1::Int
end

struct A2
@inherit_fields(A1)
a2::Int
end

struct A3
@inherit_fields(A2)
a3::Int
end

dump(A3)

Output

geek@geekbox:/home/geek$ julia tryextendingit.jl 
A3 <: Any
  a1::Int64
  a2::Int64
  a3::Int64

1 Like

Check out ObjectOriented.jl!

2 Likes

If you have a lot of common parameters, can’t they be collected in their own type, WidgetParams, which you wrap inside your individual widget types? Seems like repeating fields everywhere may violate DRY.

4 Likes

I’m not at my computer right now, but I think you’ll get an error if two property names are the same. I think if you really, really want inheritance, then the package I linked has already solved this problem. No need to reinvent the wheel.

But in general, @DNF is correct that if you have a common set of parameters, then just make that a struct that can be a field of all widgets. The. You can access fields with mywidget.params.xpos.

2 Likes

:exploding_head: :exploding_head: :exploding_head: Thank you so much !!!

Why is this not in juliapackages.org ?! Any collection of awesome Julia libraries or projects like this?

1 Like

That is another way to look at it. I did think about it actually, as a fallback to this macro. But inheritance generally makes the variable names consistent, and it is easy to write multiple dispatch functions this way. Lesser the code, lesser the bugs

1 Like

Thanks again, will check.

A common pattern is to use auxiliary functions like:

xpos(w::AbstractWidget) = w.params.xpos

to access the fields of an enclosed structure, and sometimes corresponding specific methods for special widgets that may or may not have one property.

Nothing against trying a more object-oriented structure, but sometimes it is painful to fight against the most natural language patterns.

I’m not seeing the disadvantage of an aggregated parameter field. It should be equally consistent, and no more problematic for multiple dispatch.

Yeah, now that I think of it, Maybe you are right. Will give all different paradigms a try. Only a week since I started learning Julia.

Either way, Just bowled over by how nice, easy and powerful its Meta-programming is. I actually also loved the Julian way of multiple dispatch over regular OOPs . Only thing I hadn’t liked is not being able to share constructors and needing to re enter fields over and over.

But now those seems to be solved … thanks for all the help.
(Need to tell my wife what Julia is. Else will be in trouble if I suddenly scream I :heart: Julia)

3 Likes

Glad you got it working and welcome! Yes, my partner has been confused more than once when I’m talking about Julia :joy:

2 Likes