# Default constructor for any type?

**URL:** <https://discourse.julialang.org/t/default-constructor-for-any-type/110546>\
**Category:** General Usage\
**Tags:** question\
**Created:** [February 21, 2024, 9:28pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546 "2024-02-21T21:28:50Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 9:28pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/1 "2024-02-21T21:28:50Z")

</div>

I am trying to create generic defaults in an immutable struct for a parametric type.

Say that I am trying to create a linked list, like this:

```julia
struct List{T}
    value::T
    next::RefValue{List{T}}

    List(value::_T) where {_T} = new{_T}(value, Ref{List{_T}}())
    List(next::List{_T}) where {_T} = new{_T}(zero(_T), Ref(next))
end

```

As you can see, I can always create `next` because I can just use the default constructor `Ref{List{T}}()` which works for any `T`!

But what about `T` itself? As you can see in the above example, I’m just using `zero`, because that is defined for numerical types and vectors which is what I _mostly_ care about. But what about general `T`? I don’t actually want to access `.value` if it is uninitialized, but I don’t want to have to make this a mutable struct either (giving me `undef`), because then I can’t statically compile it!

Also, you can’t statically compile `Union`, so I couldn’t get away with `Union{T,Nothing}` either.

Basically, how can I create a default or otherwise uninitialized singleton for arbitrary `T` when `zero` is not defined?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [February 21, 2024, 9:47pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/2 "2024-02-21T21:47:59Z")

</div>

> [@MilesCranmer](#):
>
> ` List(next::List{_T}) where {_T} = new{_T}(zero(_T), Ref(next))`

in this specific case I feel like this is just wrong, seems to me it should be:

```julia
List(value::_T, next::List{_T}) where {_T} = new{_T}(value,, Ref(next))

```

---

<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:** [February 21, 2024, 9:53pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/3 "2024-02-21T21:53:46Z")

</div>

What you’re trying to do doesn’t really make sense to me - your `List(::List)` constructor prepends an element(?) but doesn’t initialize that?

In general, there is no safe “default” value for arbitrary `T` that you can use - you’ll need an already existing object to prepend.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [February 21, 2024, 9:56pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/4 "2024-02-21T21:56:38Z")

</div>

I think the way to do this is to use [incomplete initialization](https://docs.julialang.org/en/v1/manual/constructors/#Incomplete-Initialization), something like this:

```julia
struct List{T}
    value::T
    next::List{T}

    List(value::T) where T = new{T}(value)
    List(value::T, list::List{T}) where T = new{T}(value, list)
end

```

```julia-repl
julia> l1 = List(1)
List{Int64}(1, #undef)

julia> l2 = List(2, l1)
List{Int64}(2, List{Int64}(1, #undef))

```

---

<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:** [February 21, 2024, 9:59pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/5 "2024-02-21T21:59:20Z")

</div>

> [@CameronBieganek](#):
>
> I think the way to do this is to use [incomplete initialization](https://docs.julialang.org/en/v1/manual/constructors/#Incomplete-Initialization), something like this:

No, that requires checking whether `next` is defined. There’s a better way for doing that, without initialization issues:

```julia
struct List{T}
    value::T
    next::Base.RefValue{List{T}}

    List(value::T, list::List{T}) where T = new{T}(value, list)
    function List(value::T) where T
          list = new{T}(value, Ref{List{T}}())
          list.next[] = list
          list
    end
end

```

When looking for the end of the list, you can check whether `list === list.next[]`. If they’re the same object, you’re at the end of the list. There’s never an uninitialized field, so you’re preserving type safety and always get a valid `List` object.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:03pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/6 "2024-02-21T22:03:56Z")

</div>

Sorry I wasn’t expecting people to discuss the type itself, I just wanted the `List` to act as a simpler discussion point.

The actual type is `Node{T}` in DynamicExpressions.jl:

> <https://github.com/SymbolicML/DynamicExpressions.jl/blob/4bd83e97d23ebb3fbde57f720b0265c5ecc33881/src/Equation.jl#L98-L112>

Which as you can see is a sum-type of four node types: a constant (with value `::T`), a feature (with index `::UInt16`), a 1-ary operator, and a 2-ary operator.

Right now it’s a mutable struct but I want to make it immutable (with `Ref` wrapping the children). However for this I will need to have a way of constructing the arbitrary `val::T`.

@jling I could take the suggestion of assuming the user will pass an example value. But maybe there’s a simpler way?

---

<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:** [February 21, 2024, 10:06pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/7 "2024-02-21T22:06:26Z")

</div>

> [@MilesCranmer](#):
>
> Right now it’s a mutable struct but I want to make it immutable (with `Ref` wrapping the children). However for this I will need to have a way of constructing the arbitrary `val::T`.

You cannot construct arbitrary `T` without already knowing what exactly that `T` is and how it should be constructed. For example, I can create a type that has no constructors:

```julia
julia> struct Foo
           a::Int
           bar() = 1
       end

julia> Foo
Foo

julia> Foo |> methods
# 0 methods for type constructor

```

So the best option is to have the user pass in the value and let them worry about creating instances of it.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:08pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/8 "2024-02-21T22:08:44Z")

</div>

But I’m not accessing it; it’s just occupying space in the struct. Presumably if it is `isbitstype` I can somehow initialize enough memory and do a `reinterpret` somehow? But is there really no cleaner way?

---

<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:** [February 21, 2024, 10:12pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/9 "2024-02-21T22:12:56Z")

</div>

Having the user pass it in _is_ the cleanest way. The `Foo` struct is just an example; I could have just as well made it like this:

```julia
julia> mutable struct Foo
           a::Vector{Int}
           bar() = 1
       end

julia> Foo |> methods
# 0 methods for type constructor

```

which still has no way to be constructed (and certainly can’t be `reinterpret`ed due to the inner pointer).

Even for `isbitstype`s, you can’t rely on `reinterpret` to do the work for you (without already knowing what exactly `T` is and how it is constructed). For example, I can create a new `primitive type Baz 8 end` where I have defined a secret/black box constructor only available in a shared C library (serving as a blackbox implementation). You cannot get a valid instance of that type because you cannot know the invariants its bitpattern must observe when constructed (that’s the secret part) - you need to go through that `ccall`, and `reinterpret` doesn’t do that.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:21pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/10 "2024-02-21T22:21:41Z")

</div>

Another issue here (besides practicality of copying around an example `val` to all my constructors) is that I would need to copy the `val::T` for every single node I create (lest having all branch nodes point to the same `val` which would make distributed c). This could end up being a huge allocation.

Is there no workaround here? I could just have this field be `Ref{T}()`, but that seems like an ugly workaround.

Is there no way I can just tell Julia to ignore that field in a struct?

For example, I can do:

```julia
julia> f(::Type{T}) where {T} = Array{T}(undef, 1);

julia> f(Vector{Int})
1-element Vector{Vector{Int64}}:
 #undef

```

Why can’t I use this `#undef` in a default constructor for the `val` field too?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:27pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/11 "2024-02-21T22:27:25Z")

</div>

I suppose one solution here is to just do

```diff
  struct Node{T} <: AbstractExpressionNode{T}
      degree::UInt8 # 0 for constant/variable, 1 for cos/sin, 2 for +/* etc.
      constant::Bool # false if variable
- val::T # If is a constant, this stores the actual value
      feature::UInt16 # If is a variable (e.g., x in cos(x)), this stores the feature index.
      op::UInt8 # If operator, this is the index of the operator in operators.binops, or operators.unaops
      l::RefValue{Node{T}} # Left child node. Only defined for degree=1 or degree=2.
      r::RefValue{Node{T}} # Right child node. Only defined for degree=2. 
+ val::T # If is a constant, this stores the actual value
  end

```

and then I can create nodes without the `val` by simply only passing the first 6 arguments. But this seems pretty arbitrary…

---

<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:** [February 21, 2024, 10:27pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/12 "2024-02-21T22:27:29Z")

</div>

> [@MilesCranmer](#):
>
> Is there no way I can just tell Julia to ignore that field in a struct?

> [@MilesCranmer](#):
>
> Why can’t I use this `#undef` in a default constructor for the `val` field too?

You can, if that `val` field is at the end of the struct, using the incomplete initialization that @CameronBieganek mentioned above. It just won’t be useful to you, since there is no actual value stored there; `#undef` means exactly that there _isn’t_ an instance; there is no valid object there (even though the field claims to have type `T`, `#undef` is _not_ a `T`!).

> [@MilesCranmer](#):
>
> Is there no workaround here? I could just have this field be `Ref{T}()`, but that seems like an ugly workaround.

If you want incomplete initialization, then you’ll have to deal with the consequences of `#undef` 🤷 Note that a `Ref` doesn’t save you from that; if a user ever gets the idea to access the `Ref` before actually storing a value, they’ll get the same error as if they had accessed an uninitialized field:

```julia
julia> Ref{Vector{Int}}()[]
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty
   @ ./Base.jl:49 [inlined]
 [2] getindex(b::Base.RefValue{Vector{Int64}})
   @ Base ./refvalue.jl:59
 [3] top-level scope
   @ REPL[1]:1

julia> struct Foo
           a::Vector{Int}
           Foo() = new()
       end

julia> Foo().a
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(x::Foo, f::Symbol)
   @ Base ./Base.jl:49
 [2] top-level scope
   @ REPL[3]:1

```

The reason for this is that just having the right amount of memory allocated is not the same as having an actual object stored in that memory. If you want that field to always contain a valid object, that field needs to be set before the constructor returns, either through mutation or by passing a valid object to `new`.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:29pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/13 "2024-02-21T22:29:43Z")

</div>

Our messages crossed 🙂 and turns out we said the same thing!

> [@Sukera](#):
>
> `#undef` means exactly that there _isn’t_ an instance; there is no valid object there (even though the field claims to have type `T`, `#undef` is _not_ a `T`!).

I don’t mind that `#undef` is not a `T`, so long as it is type stable and allows me to statically compile. Which I presume is the case here?

---

<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:** [February 21, 2024, 10:33pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/14 "2024-02-21T22:33:49Z")

</div>

> [@MilesCranmer](#):
>
> I don’t mind that `#undef` is not a `T`, so long as it is type stable and allows me to statically compile. Which I presume is the case here?

I mean, nothing mentioned so far prevents static compilation in principle, so I’m not exactly sure what you’re referring to here. You can statically compile mutable structs just fine, I’m guessing you’re more worried about a potential heap allocation? That’ll likely happen either way if `T` is not a bitstype.

You’ve mentioned at the start that you don’t want to access `.value` if it’s not initialized - but that’s _exactly_ what `#undef` is. It’s uninitialized memory, so if you ever forget to check before accessing that field and it’s not initialized, you’ll get that `UndefRefError`. If you want to be type safe there, you’ll want to make sure that this is _always_ a valid instance of a `T`, and that means having the user worry about constructing it and let them pass it in (or use a `Ref` and punt the `#undef` there, talking sternly to your users that it’s _their responsibility_ to fill it).

---

<div class="post-metadata">

**Author:** ![raminammour](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raminammour/32/13572_2.png) [@raminammour](https://discourse.julialang.org/u/raminammour)\
**Post date:** [February 21, 2024, 10:45pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/15 "2024-02-21T22:45:10Z")

</div>

> [@MilesCranmer](#):
>
> Also, you can’t statically compile `Union`, so I couldn’t get away with `Union{T,Nothing}` either.

Can you explain that statement please? I am under the impression that this pattern is safe, it is used for the iteration protocol after all.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:50pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/16 "2024-02-21T22:50:54Z")

</div>

> [@raminammour](#):
>
> Can you explain that statement please? I am under the impression that this pattern is safe, it is used for the iteration protocol after all.

By definition `Union{T,Nothing}` is type unstable which apparently is not good for static compilation as it requires type inference: [GitHub - brenhinkeller/StaticTools.jl: Enabling StaticCompiler.jl-based compilation of (some) Julia code to standalone native binaries by avoiding GC allocations and llvmcall-ing all the things!](https://github.com/brenhinkeller/StaticTools.jl?tab=readme-ov-file#limitations)

 ![Screenshot 2024-02-21 at 22.50.19](https://global.discourse-cdn.com/julialang/original/3X/e/f/eff9e98affec0638dbdc7961245c24143f2ddda9.png)

However I guess sometimes Julia gets around it? Might be related to union splitting: [Union-splitting: what it is, and why you should care](https://julialang.org/blog/2018/08/union-splitting/)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [February 21, 2024, 10:56pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/17 "2024-02-21T22:56:41Z")

</div>

Thanks. I should specify I _know_ I will never access `.val` if it’s not initialized. This is because `Node` is a sum type and you can infer `.val` is not initialized by reading the value of `.degree` and `.constant` (which are initialized).

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [February 21, 2024, 10:58pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/18 "2024-02-21T22:58:37Z")

</div>

I don’t have a very good grasp of your requirements. Could you phrase it in terms of a MWE involving a type like the following?

```julia
struct Node
    val
    l
    r
end

```

(…And add whatever type annotations you think are appropriate.)

---

<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:** [February 21, 2024, 11:06pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/19 "2024-02-21T23:06:18Z")

</div>

> [@MilesCranmer](#):
>
> I should specify I _know_ I will never access `.val` if it’s not initialized. This is because `Node` is a sum type and you can infer `.val` is not initialized by reading the value of `.degree` and `.constant` (which are initialized).

My point is that `Node` (to Julia!) is _not_ a sum type. It’s a regular product type, as all `struct`s are, and the language does not help you in any way to preserve that invariant coupling between fields. If there’s ever a path through your code that accesses `.val` without properly checking the other fields first (or, by some third party just accessing the field with the wrong assumptions), you will sooner or later hit that `UndefRefError`. The safest option is then to make sure it’s always valid, by either requiring it to be passed in or accepting the type instability and representing the “uninitialized” state with a different type from the “initialized” state.

The general idea for this sort of transition (from ad-hoc, loosely enforced couplings to type-safe abstractions) is called “Making illegal states unrepresentable”. In Julia, at the moment that unfortunately means type instability, because we don’t really have the tools to properly enforce these invariants.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [February 21, 2024, 11:32pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/20 "2024-02-21T23:32:31Z")

</div>

> [@Sukera](#):
>
> In general, there is no safe “default” value for arbitrary `T` that you can use - you’ll need an already existing object to prepend.

Exactly what I was thinking, but even for numeric types, if restricting to those:

> [@MilesCranmer](#):
>
> I’m just using `zero`, because that is defined for numerical types

I wouldn’t rely on that (rather `one`?) for all types, e.g. Rust has [NonZeroU8 in std::num - Rust](https://doc.rust-lang.org/std/num/struct.NonZeroU8.html) (to make division by zero impossible…), and I’ve been thinking if Julia should have such a type, at least available, if not in Base.

```julia
julia> one(String) # wasn't sure what to expect, or that zero not defined
""

julia> zero(String)
ERROR: MethodError: no method matching zero(::Type{String})

```

There’s a good recent video (or at least to me) about “constructors broken” in C++, vs in Rust (i.e. factories better), and I meant to post a link, think more if it applies to Julia too.

> [@MilesCranmer](#):
>
> I am trying to create a linked list

It’s usually the wrong structure (while your problem more general to all containers, also likely for below), and famously hard in Rust…:

> **[Introduction - Learning Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/)**
>
> Learning Rust With Entirely Too Many Linked Lists

[Next page](https://discourse.julialang.org/t/default-constructor-for-any-type/110546.md?page=2)
