# Learning Julia by (ab)using constructor

**URL:** <https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485>\
**Category:** New to Julia\
**Created:** [December 28, 2020, 1:20am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485 "2020-12-28T01:20:17Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![codyit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/codyit/32/20590_2.png) [@codyit](https://discourse.julialang.org/u/codyit)\
**Post date:** [December 28, 2020, 1:20am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/1 "2020-12-28T01:20:17Z")

</div>

I’ve just been trying to pick up Julia this morning.  
And I thought, what’s better than abusing so struct behaves like Python class!

Totally understand things are preferably immutable, and methods declaration are external to structs etc. But just for the sake of curiosity and learning:

1. Is there a more succinct way to define the inner constructor to achieve the same as below code?
2. What’s the meaning of defining variables or functions in the struct (but outside of constructor) scope? Only to be used in inner constructor?

```julia
julia> mutable struct C
           id::String
           speak::Function
           self::C

           f(self::C, word::String) = println("I'm $(self.id) yeah. $word.")
           function C(id::String) 
               instance = new(id)
               instance.speak = (word::String) -> f(instance, word)
               instance.self = instance
           end
       end

julia> julia = C("julia")
C("julia", var"#5#7"{C,var"#f#6"}(C(#= circular reference @-2 =#), var"#f#6"()), C(#= circular reference @-1 =#))

julia> julia.speak("hey")
I'm julia yeah. hey.

julia> julia.id = "eve"
"eve"

julia> julia.speak("yo")
I'm eve yeah. yo.

```

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [December 28, 2020, 2:24am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/2 "2020-12-28T02:24:17Z")

</div>

Welcome!

> [@codyit](#):
>
> Is there a more succinct way to define the inner constructor to achieve the same as below code?

You can use `@with_kw` from [Parameters.jl](https://github.com/mauro3/Parameters.jl) to define your default values like:

```julia
@with_kw mutable struct C
  id::String
  speak::Function = (word) -> println(id, word)
end

```

(I’ve shortened your example a bit, but hopefully the idea makes sense).

> [@codyit](#):
>
> What’s the meaning of defining variables or functions in the struct (but outside of constructor) scope? Only to be used in inner constructor?

I guess you could use it for that–it’s extremely unusual to define anything inside the struct other than its fields, and I don’t think I’ve ever seen it done in Julia code in the wild. It’s not something I’ve ever needed, particularly because as soon as you start putting your behavior _outside_ of your structs, it doesn’t really make sense.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [December 28, 2020, 3:23am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/3 "2020-12-28T03:23:18Z")

</div>

It’s worth noting that `Function` is an abstract type, every function has it’s own type which is a subtype of `Function`. If you want your struct to have concrete storage, you can parameterize it by the type of the function, e.g.

```julia
@with_kw mutable struct C{F}
  id::String
  speak::F = (word) -> println(id, word)
end

```

or you could just abuse `getproperty` to add methods:

```julia
julia> mutable struct C
           id::String
       end

julia> function Base.getproperty(self::C, s::Symbol)
           if s === :speak
               word -> println("I'm $(self.id) yeah. $word.")
           else
               getfield(self, s)
           end
       end

julia> julia = C("julia")
C("julia")

julia> julia.speak("hi")
I'm julia yeah. hi.

```

---

<div class="post-metadata">

**Author:** ![codyit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/codyit/32/20590_2.png) [@codyit](https://discourse.julialang.org/u/codyit)\
**Post date:** [December 28, 2020, 5:12am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/4 "2020-12-28T05:12:52Z")

</div>

Thanks fellas! I think I’ve learned more than I set out for.

Less importantly, after looking at Parameters.jl [examples](https://github.com/mauro3/Parameters.jl/blob/master/examples/ex1.jl) and the implementation a bit turns out there’s seems to be no easy way to combine `@with_kw` with [self referential](https://docs.julialang.org/en/v1/manual/constructors/#Incomplete-Initialization) construction

(I was trying to game it so method call outcome changes based on instance state without it being supplied as argument just like Python, thus the `self`)

The best (without spending a lot of time) I can come up with is something like this but it isn’t nice because I’m redefining `speak()` which changes the type so it only works when it’s abstract:

```julia
using Parameters

@with_kw mutable struct J
  id::String
  self::Union{J, Nothing} = nothing
  speak::Function = (self::J, word::String) -> println(self.id, word)
  J(id, self, speak) = (ins = new(id, self, speak); ins.speak = (word) -> speak(ins, word); ins.self = ins)
end

```

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [December 28, 2020, 7:38am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/5 "2020-12-28T07:38:29Z")

</div>

Yeah, you’re really fighting the language here by trying to put behavior inside your structs. Life will be much easier if you let that notion go:

```julia
julia> mutable struct J
         id::String
       end

julia> speak(self::J, word::String) = println(self.id, word)
speak (generic function with 1 method)

julia> j = J("hello")
J("hello")

julia> speak(j, "world")
helloworld

```

Putting the behavior outside of the struct…

- Eliminates the need to use `@with_kw` at all
- Removes the unnecessary `self` field
- Allows us to skip writing the constructor
- Allows other implementations of `speak` for other types to be implemented later.
- Improves performance by avoiding the entire issue of the abstract `speak::Function` field type.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [December 28, 2020, 8:14am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/6 "2020-12-28T08:14:39Z")

</div>

This is of course true if your goal is to achieve something productive. Sometimes it’s fun and educational to tinker though.

---

<div class="post-metadata">

**Author:** ![codyit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/codyit/32/20590_2.png) [@codyit](https://discourse.julialang.org/u/codyit)\
**Post date:** [December 28, 2020, 8:45am UTC](https://discourse.julialang.org/t/learning-julia-by-ab-using-constructor/52485/7 "2020-12-28T08:45:14Z")

</div>

Absolutely, just gaming it to learn as said.

For a real life use case of self referential struct having default value I think it might be useful for certain kind of tree nodes say?

Anyway.  
Love to see the language can indeed express obscure things outside of idiomatic approach with relative ease.  
Love to see I’m getting reply here. Thank you.  
And of course multi dispatch, which is why I’m drawn here. (I started using Kotlin at work a year ago, think it’s amazing, a bit more functional, less OO, If only it supports multi dispatch, would get rid of a lot of “design patterns” - boiler plates)

I think my next project would most likely be in Julia. Even for a case like backend web service, I have a feeling the pros would outweigh the cons, e.g. comparatively less mature frameworks (routes + authn/z + openapi code generation, cloud clients etc…), I can see the pieces out there just expecting there would be more work to stitches them together or help patch things up.

❤
