# O.O.P in Julia

**URL:** <https://discourse.julialang.org/t/o-o-p-in-julia/124957>\
**Category:** General Usage\
**Created:** [January 20, 2025, 11:09am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957 "2025-01-20T11:09:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gilles\_Dubois](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gilles_dubois/32/25830_2.png) [@Gilles\_Dubois](https://discourse.julialang.org/u/Gilles_Dubois)\
**Post date:** [January 20, 2025, 11:09am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/1 "2025-01-20T11:09:00Z")

</div>

Hello everybody,  
I already used the ‘struct’ as an equivalent of class (say for Python or C++, or …) but I didn’t find what is the trick of Julia to emulate the ‘class-variable’ that is the variable which belongs to all instances of the class and is shared between them.  
Can you give an answer to such simple question ? Of course forget about ‘global variables’ which is quick and dirty. May-be space-names or something like ?  
Thank you !

---

<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:** [January 20, 2025, 11:10am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/2 "2025-01-20T11:10:47Z")

</div>

There are some libraries for doing this. For example:

- [GitHub - Suzhou-Tongyuan/ObjectOriented.jl: Conventional object-oriented programming in Julia without breaking Julia's core design ideas](https://github.com/Suzhou-Tongyuan/ObjectOriented.jl)
- [GitHub - rjplevin/Classes.jl: A simple, Julian approach to inheritance of structure and methods](https://github.com/rjplevin/Classes.jl)

But read this first: [Translating OOP into Idiomatic Julia · ObjectOriented.jl](https://suzhou-tongyuan.github.io/ObjectOriented.jl/dev/how-to-translate-oop-into-julia/)

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [January 20, 2025, 11:18am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/3 "2025-01-20T11:18:45Z")

</div>

Julia is not Object Oriented as you might see in Java or C#. `struct` is not like a class - there are no builtin ways to have a variable shared between all instances of a given struct. You can give all instances a `Ref` to the same object in their constructor, but there is no builtin way of doing this.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [January 20, 2025, 11:20am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/4 "2025-01-20T11:20:02Z")

</div>

I don’t think global variables are considered quick and dirty in Julia. In fact, I would say global variables are often used for “private class variables” (that is, variables that do not belong to a particular instance and are not part of the user API). I used that in Decimals.jl to “re-use” some instances of `BigInt`s ([Decimals.jl/src/bigint.jl at 463869785a1789edcc5181c565e3d28e7516350e · JuliaMath/Decimals.jl · GitHub](https://github.com/JuliaMath/Decimals.jl/blob/463869785a1789edcc5181c565e3d28e7516350e/src/bigint.jl#L7-L9))

In the case of “public class variables” (that is, variables that do not belong to a particular instance and are part of the user API), they can be implemented as functions. Again, an example from Decimals.jl is the `Base.precision` function ([Decimals.jl/src/context.jl at 463869785a1789edcc5181c565e3d28e7516350e · JuliaMath/Decimals.jl · GitHub](https://github.com/JuliaMath/Decimals.jl/blob/463869785a1789edcc5181c565e3d28e7516350e/src/context.jl#L36)).

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [January 20, 2025, 12:09pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/5 "2025-01-20T12:09:32Z")

</div>

There is a way which mimics a class variable via the `getproperty`/`setproperty!` functions. Whenever you do something like `a.b` it is lowered to `getproperty(a, :b)`, and whenever to you do something like `a.b = c`, it’s lowered to `setproperty!(a, :b, c)`. You can make your own extension like e.g.

```julia
const classvar = Ref(0)
struct MyStruct
    foo::Int
    bar::Float64
end

@inline function Base.getproperty(a::MyStruct, b::Symbol)
    if b == :classvariable
        return classvar[]
    else
        return getfield(a, b)
    end
end

@inline function Base.setproperty!(a::MyStruct, b::Symbol, x)
    if b == :classvariable
        classvar[] = x
    else
        setfield!(a, b, x)
    end
end

a = MyStruct(1, 2.3)
b = MyStruct(2, 3.5)
a.classvariable = 4
b.classvariable == 4 # true

```

I made the global `classvar` a const `Ref`, this makes the compiler happy. If you care about memory ordering, there is an additional argument to the property functions, see their docs. You may of course call the global whatever you like, to avoid mess, e.g. `var"##MyStruct var 1"`.

You can get autocompletion by extending `propertynames`:

```julia
Base.propertynames(a::MyStruct) = (fieldnames(MyStruct)..., :classvariable)

```

---

<div class="post-metadata">

**Author:** ![karei](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/karei/32/214809_2.png) [@karei](https://discourse.julialang.org/u/karei)\
**Post date:** [January 20, 2025, 12:47pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/6 "2025-01-20T12:47:26Z")

</div>

I would choose to create a new type that holds the common fields and include an instance of this in each of the structs that needs the common fields. As [Classes.jl](https://github.com/rjplevin/Classes.jl) said.

The following is a pure julia implementation.

```julia
struct SharedVariables
    a::Int
    b::Vector{Int}
end

const shared = SharedVariables(1,[1,2])

struct Mystuct
    shared::SharedVariables
    c::Int
    function Mystuct(c)
        new(shared, c)
    end
end

x = Mystuct(9)
x.c # 9
x.shared.a # 1

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2025, 12:48pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/7 "2025-01-20T12:48:53Z")

</div>

But please don’t do this! (adding `getproperty`) methods.

The performance is bad, its not very composable and will give you a lot of pain when you want to refactor. It should be considered an anti-pattern unless you have very good user-experience reasons for it.

Instead of using hacks to get OOP patterns, learn multiple dispatch. Many of us tried to follow OOP styles when we came to Julia and later removed it all.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [January 20, 2025, 12:59pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/8 "2025-01-20T12:59:57Z")

</div>

> [@Raf](#):
>
> The performance is bad

The getproperty stuff is taken care of at compile time. Usually no performance problems. It compiles to a `mov`.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2025, 1:00pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/9 "2025-01-20T13:00:32Z")

</div>

```julia
x = Mystuct(9)
x.c # 9
x.shared.a # 1

```

Additionally, accessing fields directly like this will get in the way of object composition. Outside of the simplest cases its better to access fields with methods:

```julia
a(x) = x.a

```

Then you can refactor out shared objects and do this:

```julia
a(x::MyStruct) = a(x.shared)

```

And the rest of your code will keep working without change.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2025, 1:03pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/10 "2025-01-20T13:03:33Z")

</div>

This is not necessarily true except in the simplest of cases. I have seen massive type instability in code bases using oop style getproperty in big if/elseif blocks.

Its making const propagation and other compiler optimisations a lot harder than it needs to be, and at some point that will have a cost.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [January 20, 2025, 1:14pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/11 "2025-01-20T13:14:31Z")

</div>

> [@Raf](#):
>
> This is not necessarily true except in the simplest of cases. I have seen massive type instability in code bases using oop style getproperty in big if/elseif blocks.

I can imagine that. If it’s not run at compile time there will be problems. It should perhaps be marked with `Base.@assume_effects :foldable` instead of `@inline`. (It will be called with a compile time field name if called from a dot notation access.) And used for fields, not for calling funny functions (which might be tempting for OOP people).

Otherwise I agree that it’s not a universal OOP emulator, but for this particular use, class variables, I think it’s quite useful.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 20, 2025, 1:24pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/12 "2025-01-20T13:24:14Z")

</div>

The fact our compiler can “give up” on resolving types (and just box instead) needs to be constantly accounted for and avoided. But yes marking as `:foldable` may help, but maybe not if you have some type instability or union fields

---

<div class="post-metadata">

**Author:** ![Gilles\_Dubois](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gilles_dubois/32/25830_2.png) [@Gilles\_Dubois](https://discourse.julialang.org/u/Gilles_Dubois)\
**Post date:** [January 20, 2025, 4:11pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/13 "2025-01-20T16:11:40Z")

</div>

Thank you all for your very reactive attitude and numerous and various answers. Of course it will take some time before I can read (and understand) every point of view and suggested attitude. I’m not in a rush and I will take time. Of course I will add some message asking for additional information if I find something not clear.  
In my country they allow till end of January for New Year wishes. So I will use this possibility. Happy New Year everybody.  
Gilles

---

<div class="post-metadata">

**Author:** ![Gilles\_Dubois](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gilles_dubois/32/25830_2.png) [@Gilles\_Dubois](https://discourse.julialang.org/u/Gilles_Dubois)\
**Post date:** [January 20, 2025, 4:12pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/14 "2025-01-20T16:12:52Z")

</div>

Very interesting suggestion, thanks !

---

<div class="post-metadata">

**Author:** ![Gilles\_Dubois](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gilles_dubois/32/25830_2.png) [@Gilles\_Dubois](https://discourse.julialang.org/u/Gilles_Dubois)\
**Post date:** [January 20, 2025, 4:22pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/15 "2025-01-20T16:22:28Z")

</div>

> [@Sukera](#):
>
> Julia is not Object Oriented as you might see in Java or C#. `struct` is not like a class

Yes, I know. That’s why my question. I’m looking for a clean ‘mimic’ not to transform Julia into a Python dialect.

OOP is an intersesting and useful concept although I understand that in some cases it can be a constraint and even confusing. So the good attitude is to use it whenever it is suited. A bit of OOP style can improve the structure of a program.

Whe, it comes to polymorphism ,multiple inheritance, freindship between classes, etc Java and C++ and the rest begin to be quite obscure.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [January 20, 2025, 4:24pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/16 "2025-01-20T16:24:33Z")

</div>

It’s possible for `getproperty` to be efficient. But it’s also easy to get uninferrable code. This took a little work to get right in [DotCall.jl](https://github.com/jlapeyre/DotCall.jl)

A lot of Julia code works well without these OOP conveniences. But sometimes it would make things much simpler and more convenient to have them. I’m tempted to use them sometimes, but never do because it’s not idiomatic Julia. I disagree with the idea that you lose nothing by giving up the class-based OOP conveniences. This has been discussed quite a few times in this forum.

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [January 20, 2025, 4:48pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/17 "2025-01-20T16:48:26Z")

</div>

As many have already pointed out, it is possible to emulate OOP, but it is generally an antipattern when multiple dispatch with type hierarchy would be a better fit. I would also strongly recommend having a look at [Hands-On Design Patterns and Best Practices with Julia](https://www.everand.com/book/498887301/Hands-On-Design-Patterns-and-Best-Practices-with-Julia-Proven-solutions-to-common-problems-in-software-design-for-Julia-1-x) for learning how code can be organised in Julia.

> [@Gilles\_Dubois](#):
>
> I didn’t find what is the trick of Julia to emulate the ‘class-variable’ that is the variable which belongs to all instances of the class and is shared between them.

There are many ways to approach this in Julia, depending on what sharing means. When shared variables are supposed to be immutable, one can create an ordinary parameter struct and add it to the instance when it is constructed. If all instances always need to share the same value, then a global constant would be a better fit.

In case sharing means that one should be able to listen or even modify the thing, then `Ref` can be used as well as `mutable struct` (remember about using locks though). If all instances share the same resource, like a database, GUI window instance, or HTTP router, then putting those things in a global variable makes sense. The module namespace then serves the same purpose as the class singleton.

When these options become limiting and repetitive, I would recommend looking into macros.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 20, 2025, 6:14pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/18 "2025-01-20T18:14:24Z")

</div>

> [@Raf](#):
>
> The performance is bad

A method is just as good for getting information associated with a type like a class variable does and it doesn’t lose in performance. If it’s a type-wise constant or a freshly computed value, then it doesn’t even need to be cached separately from the type. Happens all the time in Julia e.g. `eltype`.

---

<div class="post-metadata">

**Author:** ![cdawg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cdawg/32/9811_2.png) [@cdawg](https://discourse.julialang.org/u/cdawg)\
**Post date:** [January 21, 2025, 9:43am UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/19 "2025-01-21T09:43:43Z")

</div>

Interesting discussion on the inference, reminds me of [Mapping a 'getter' - #16 by Marco\_Antoniotti](https://discourse.julialang.org/t/mapping-a-getter/107276/16) . I guess the problem, and the difference with very fast struct.field is that getproperty cant dispatch on the value of symbol. The constant propagation is neccesary for speed, and constant propagation cannot be counted on (yet) it is only offered as a convenience when it works.

Buuuut it seems to get better every release! Is there a chance that the antipattern will become a pattern in the future? Until then there is Lazy.jl and @forward and other ways of mimicing accessors that can dispatch.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [January 21, 2025, 2:52pm UTC](https://discourse.julialang.org/t/o-o-p-in-julia/124957/20 "2025-01-21T14:52:59Z")

</div>

This post was temporarily hidden by the community for possibly being off-topic, unfocused, inappropriate, or spammy.

[Next page](https://discourse.julialang.org/t/o-o-p-in-julia/124957.md?page=2)
