# 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:** 2

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [February 22, 2024, 12:29am UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/21 "2024-02-22T00:29:28Z")

</div>

It’s been suggested to allow `new(..., undef, ...)` for leaving an arbitrary struct field uninitialized (ideally also deprecating the current way of doing partial initialization, which is a tried and true footgun when iterating on struct layouts). Mentioned in [Warn on uninitialized isbits-fields in structs? · Issue #24943 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/24943) and [Semantics of `Expr(:new)` underspecified · Issue #26764 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/26764).

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 22, 2024, 12:38pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/22 "2024-02-22T12:38:11Z")

</div>

> [@Palli](#):
>
> ```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})
> 
> ```

Incidentally, this exists due to the reasoning which uses `*` for String concatenation: we want `t::T * one(T) == t` for all `t isa T`, for all `T`.

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [February 22, 2024, 1:37pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/23 "2024-02-22T13:37:09Z")

</div>

I’m not sure if this is the right approach, but i would do something like:

```julia
function defaultof end

defaultof(::Type{T}) where {T <: Number} = zero(T)
defaultof(::Type{String}) = ""
# implement defaultof for more types

```

Expose `defaultof` to be extend by the user for their custom types. Then, define the constructor as:

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

```

As an example, if a user defines a custom type such as:

```julia
struct Rect
    x::Float64
    y::Float64
    w::Float64
    h::Float64
end

```

`defaultof` should be implemented for that type:

```julia
defaultof(::Type{Rect}) = Rect(0, 0, -1, -1)

```

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [February 22, 2024, 4:50pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/24 "2024-02-22T16:50:18Z")

</div>

> [@MilesCranmer](#):
>
> Right now it’s a mutable struct but I want to make it immutable (with `Ref` wrapping the children).

Why? (Wondering if this is an X-Y problem.)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [February 23, 2024, 4:08am UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/25 "2024-02-23T04:08:38Z")

</div>

> [@MilesCranmer](#):
>
> ```julia
> struct List{T}
> value::T
> next::Ref{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
> 
> ```

I haven not read through the whole thread yet, but I do want to point out that `Ref` is an abstract type. You should probably refer to the concrete type `Base.RefValue` as the type of the field.

```julia
struct List{T}
    value::T
    next::Base.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

```

To address your original question, let’s say we have a type that is impossible to construct directly as follows:

```julia-repl
julia> struct Foo
           x::Int
           y::UInt8
           z::Float32
           function Foo end
       end

julia> methods(Foo)
# 0 methods for type constructor

julia> Foo(1, 0x1, 1.f0)
ERROR: MethodError: no method matching Foo(::Int64, ::UInt8, ::Float32)
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

```

Since we know the size `Foo`, we can construct `Foo` another way.

```julia-repl
julia> sizeof(Foo)
16

julia> foo = first(reinterpret(Foo, zeros(UInt8, sizeof(Foo))))
Foo(0, 0x00, 0.0f0)

```

Note that the above only works for bitstypes.

```julia-repl
julia> mutable struct Bar
           x::Int
           y::UInt8
           z::Float32
           function Bar end
       end

julia> bar = first(reinterpret(Bar, zeros(UInt8, sizeof(Foo))))
ERROR: ArgumentError: cannot reinterpret `UInt8` as `Bar`, type `Bar` is not a bits type
...

```

We can use another approach, but this now requires `unsafe_load`.

```julia-repl
julia> let z = zeros(UInt8, sizeof(Bar))
           GC.@preserve z unsafe_load(Ptr{Bar}(pointer(z)))
       end
Bar(0, 0x00, 0.0f0)

```

---

<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 23, 2024, 6:21am UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/26 "2024-02-23T06:21:21Z")

</div>

> [@mkitti](#):
>
> To address your original question, let’s say we have a type that is impossible to construct directly as follows:

What you’ve written has already been discussed further up.

> [@mkitti](#):
>
> We can use another approach, but this now requires `unsafe_load`.

As the name says, this is unsafe, here not because of memory safety (everything is properly GC tracked) but because you’re breaking any potential invariants of `Foo`. From the POV of Julia, there is no constructor, so there is no valid way to construct an instance of type `Foo`. It’s the same as the primitive type example from above.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [February 23, 2024, 7:04am UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/27 "2024-02-23T07:04:41Z")

</div>

Are you sure that you can’t have a small union field?

> [@Successful Static Compilation of Julia Code for use in Production](https://discourse.julialang.org/t/successful-static-compilation-of-julia-code-for-use-in-production/79318/1):
>
> Another, inferior, option would be to instead `return Float64(s)` at the end. This makes the output type possible to infer and the compilation goes through, leaving an internal type instability.

From this write up, it looks like static compilation can handle some localized instability. You might have to type annotate the call sites potentially?

---

<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 23, 2024, 2:16pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/28 "2024-02-23T14:16:46Z")

</div>

As an example, here are all the annotations I had to use in my code when I had `Union{T,Nothing}`: [Remove old uses of `.val::T` · SymbolicML/DynamicExpressions.jl@c5417ee · GitHub](https://github.com/SymbolicML/DynamicExpressions.jl/commit/c5417ee1cab505319cec5042f043f5d443f8b157) to get full optimization.

Now I just leave `.val` undefined (because it’s in a mutable struct). But I would like to use immutable structs for a variety of reasons – (1) fewer allocations; (2) better optimizations, as code can safely assume a field won’t change; (3) maybe better interfacing with static compilation (though from this thread I think this assumption might be wrong?). I guess I can put the `val` at the end and get this to work, but it seems sort of a code smell relative to if I could just use a formal `undef` (which presumably would not cause the type instabilities I am showing above).

---

<div class="post-metadata">

**Author:** ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)\
**Post date:** [February 23, 2024, 2:42pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/29 "2024-02-23T14:42:11Z")

</div>

> [@MilesCranmer](#):
>
> (2) better optimizations, as code can safely assume a field won’t change

If you have fields that won’t change, you can tag them as `const` in your mutable type to aid the compiler. Manual ref

```julia
julia> mutable struct Baz
           a::Int
           const b::Float64
       end

julia> baz = Baz(1, 1.5);

julia> baz.a = 2
2

julia> baz.b = 2.0
ERROR: setfield!: const field .b of type Baz cannot be changed
[...]

```

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 23, 2024, 3:05pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/30 "2024-02-23T15:05:53Z")

</div>

> [@MilesCranmer](#):
>
> The actual type is `Node{T}`

Sorry for being offtopic, but you should strongly consider reordering the fields to

```julia
mutable struct Node{T} <: AbstractExpressionNode{T}
    degree::UInt8 # 0 for constant/variable, 1 for cos/sin, 2 for +/* etc.
    constant::Bool # false if variable
    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

    val::T # If is a constant, this stores the actual value

```

The reason is structure padding. If e.g. T is a mutable struct, then your Node will waste 6 bytes before `val`, and 5 bytes after `op`. If you reorder, you only have 3 bytes of structure padding after `op` before `val`.

> [@Sukera](#):
>
> 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:

You definitely can construct arbitrary T without knowing them, that’s how lots of serialization/deserialization packages like stdlib or jld2 work.

A simple example is

```julia
julia> @generated foo(::Type{T}) where T = Expr(:new, T)
julia> struct A
       x::Int
       end
julia> foo(A)
A(133928310153792)

julia> mutable struct B
       x::String
       end

julia> foo(B)
B(#undef)

```

Safety of that technique is debatable, but this is possible if needed.

---

<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 23, 2024, 3:51pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/31 "2024-02-23T15:51:42Z")

</div>

> [@foobar\_lv2](#):
>
> You definitely can construct arbitrary T without knowing them, that’s how lots of serialization/deserialization packages like stdlib or jld2 work.

Serialization is a special case, because (under the assumption that the serialization step was correct) the deserialization has known-valid data. This is not the case here though - this thread debates constructing _new & valid_ objects for arbitrary `T`, which you can’t do without knowing how that is done for any particular `T`. Serialization sidesteps that problem by requiring a valid constructed object to exist in the first place.

Serialization also has an additional complication in that it’s invalid to preserve interior pointers (since they’re process-local), so those are lost, even if the object was initially valid. In order to reconstruct them, the serialization library needs to know how to properly serialize & deserialize objects of that type, meaning it needs to specialize for that type again.

---

<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 23, 2024, 3:58pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/32 "2024-02-23T15:58:40Z")

</div>

> [@sbuercklin](#):
>
> ```julia
> julia> mutable struct Baz
> a::Int
> const b::Float64
> end
> 
> ```

![Video gif. A man uses his hands to imitate his mind being blown and fireworks and explosions are overlaid in front of him.](https://global.discourse-cdn.com/julialang/original/3X/c/d/cdc0ede6efd37a935826cf1cc221679ddbc07c76.gif)  
This is awesome, I literally had no idea! Will certainly start using that in my code 😃

Although unfortunately it looks like this is only v1.8+?

Quick followup - are there any reasons I would want to do something like the following instead of the example you sent?

```julia
struct Baz
    a::RefValue{Int}
    b::Float64
end

```

For example, is one better for allocations than the other?

---

<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 23, 2024, 4:03pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/33 "2024-02-23T16:03:41Z")

</div>

Cool! Thanks. This seems like a full solution. I suppose I can also just have default behaviour set up for most common types, like `foo(::Type{T}) where {T<:Number} = one(T)`, etc., (to avoid generating expressions for all types) and then users can declare custom initializers if needed.

---

<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 23, 2024, 4:07pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/34 "2024-02-23T16:07:37Z")

</div>

> [@MilesCranmer](#):
>
> Thanks. This seems like a full solution.

I implore you not to use this. To quote [the devdocs](https://docs.julialang.org/en/v1/devdocs/ast/#Expr-types):

> - `new`  
> Allocates a new struct-like object. First argument is the type. The [`new`](https://docs.julialang.org/en/v1/base/base/#new) pseudo-function is lowered to this, and the type is always inserted by the compiler. This is very much an internal-only feature, and does no checking. Evaluating arbitrary `new` expressions can easily segfault.

This is not a stable thing to build a package off of.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 23, 2024, 5:13pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/35 "2024-02-23T17:13:36Z")

</div>

> [@MilesCranmer](#):
>
> Cool! Thanks. This seems like a full solution.

Sure you can do this for most types.

But take care to remember that safety is debatable, e.g. `foo(BigInt)` is liable to spawn bats, segfault or corrupt memory and install ransomware and shut down your workplace.

(i.e. you need to document that T should not be parametrized with stuff types holding foreign pointers like e.g. BigInt)

---

<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 23, 2024, 7:25pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/36 "2024-02-23T19:25:59Z")

</div>

> [@foobar\_lv2](#):
>
> (i.e. you need to document that T should not be parametrized with stuff types holding foreign pointers like e.g. BigInt)

It’s more insidious than that - your users _MUST NOT_ (and I mean that in the RFC “should never ever EVER happen” kind of way) assume that whatever they get out from this is actually a valid instance of that type, even for `isbitstype`. Using `Expr(:new)` like that is bypassing any and all potential checks that normally happen when constructing an object of that type.

In the best worst-case, this leads to extremely difficult to debug heisenbugs due to now-broken assumptions the owner of that type made in its usage. Or the compiler made! If the compiler assumes that all instances must come from one of its lowered constructors and you bypass that, pretty much anything can happen when the compiler decides to abstractly interpret this.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 23, 2024, 8:52pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/37 "2024-02-23T20:52:29Z")

</div>

It should be possible to create default constructors in a not-insane way through a tactic like the following:

- Primitive values are `zero(T)` or `one(T)`.
- Containers (`UnionAll`) are an empty example of the container, constrained to the given type parameters, defaulting to `Any`.
- Refs are a reference to a default value of their type parameter.
- Unions are a default value of the leftmost type.
- Singleton types are themselves.
- Tuples are a tuple of the provided type’s defaults.
- Types are `Union{}`.
- Structs call the constructor on default values for the fields (this only works consistently if there’s a constructor in the default form).
- `::Function` is `identity`, or for a concrete subtype, the only instance of that subtype.

I think that covers all the bases, right? To make it work consistently you’d need to examine the method table for structs and pick one, rather than assume they have a default constructor. But the principle remains the same.

It sounds like a lot of work to really get it right and cover all the edge cases, but the result would be a worthy package with a number of practical uses.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 23, 2024, 9:23pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/38 "2024-02-23T21:23:43Z")

</div>

> [@Sukera](#):
>
> If the compiler assumes that all instances must come from one of its lowered constructors and you bypass that, pretty much anything can happen when the compiler decides to abstractly interpret this.

This is no worse or better than reinterpret or `Vector{T}(undef, 1)[1]`.

My favorite example of weirdness from that are structs containing Bool. The compiler/runtime are very sure that the leading 7 bit of Bool are zero. They are, in fact, so sure that having anything else leads to UB with fun schizophrenic optimizations, and of course divergence of behavior between interpreted and compiled code, and of course divergence of behavior depending on success of type inference.

You can observe that funhouse by reinterpreting:

```julia
julia> struct B
       b::Bool
       end

julia> a=UInt8[127]
1-element Vector{UInt8}:
 0x7f

julia> b=reinterpret(B, a)
1-element reinterpret(B, ::Vector{UInt8}):
 B(true)

julia> b[1]
B(true)

julia> b[1].b == true
true

julia> foo(b)=b[1].b==true
foo (generic function with 1 method)

julia> foo(b)
false

```

But seriously, I think this is the only example where you get honest-to-god UB from badly initialized bitstypes?

> [@mnemnion](#):
>
> It should be possible to create default constructors in a not-insane way through a tactic like the following:

No. There is no way.

Either make your field `Union{T, Nothing}` (this is not bad for performance), ask your users to not parametrize this with bad types, or simply don’t access invalid data.

For the BigInt example, you need to make sure that the REPL display code checks whether the bigint is valid before trying to print it (e.g. by having other logic that dictates that) – the printing code is the thing that can memory corrupt on access (because the underlying MPZ library assumes a valid pointer to whatever datastructures it has. If you instead fill it with uninitialized garbage you can end up with a pointer to somewhere on the heap containing other data…).

---

<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 23, 2024, 9:29pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/39 "2024-02-23T21:29:24Z")

</div>

> [@mnemnion](#):
>
> I think that covers all the bases, right?

No, you cannot assume that all primitive values have a `zero` OR a `one`. For example, the structs you can define through [FieldFlags.jl](https://discourse.julialang.org/t/ann-fieldflags-jl-bitfield-like-structs/100594) have no defined “default value”. They’re not even numeric at all, and don’t even have a zero initializer! There used to be one, but it caused some problems downstream precisely because assuming that all-zero is valid is not good.

That’s why I say that this is not possible for arbitrary `T`; you need to know what that `T` is to even be able to tell whether there could be a default value.

> [@mnemnion](#):
>
> To make it work consistently you’d need to examine the method table for structs and pick one, rather than assume they have a default constructor. But the principle remains the same.

That veers more into the area of fuzzing (something one could do with [PropCheck.jl](https://discourse.julialang.org/t/ann-propcheck-jl/101481), or soon better with an upcoming package of mine), but that brings its own problems - what if the constructor throws an error? Or worse yet, crashes julia? That’s not as absurd as it sounds, I’ve hit exactly that problem trying to do this before:

> <https://github.com/JuliaLang/julia/issues/37630>
>
> Hi!
> 
> The code for generating crashes can be found \[in this gist\](https://gist.…github.com/Seelengrab/5987c05f8184f2ef856396870a509a3d). Simply include that and run \`generate(Any)\` to (non-deterministically, sadly) crash julia with something similar to this (with varying degrees of depth, depending on how deep the \`generate\` rabbit hole goes):
> 
> \`\`\`
> Unreachable reached at 0x7f370cbe36d2
> 
> signal (4): Illegal instruction
> in expression starting at none:1
> generate at /home/\<snip\>/PropCheck/src/PropCheck.jl:105
> iterate at ./generator.jl:47 \[inlined\]
> collect\_to! at ./array.jl:732
> collect\_to\_with\_first! at ./array.jl:710
> unknown function (ip: 0x7f370cbe3682)
> collect at ./array.jl:691
> generate at /home/\<snip\>/PropCheck/src/PropCheck.jl:105
> generate at /home/\<snip\>/PropCheck/src/PropCheck.jl:111
> iterate at ./generator.jl:47 \[inlined\]
> collect at ./array.jl:686
> generate at /home/\<snip\>/PropCheck/src/PropCheck.jl:105
> generate at /home/\<snip\>/PropCheck/src/PropCheck.jl:88
> top-level scope at ./none:1
> jl\_toplevel\_eval\_flex at /home/\<snip\>/julia/src/toplevel.c:834
> jl\_toplevel\_eval\_flex at /home/\<snip\>/julia/src/toplevel.c:790
> jl\_toplevel\_eval\_flex at /home/\<snip\>/julia/src/toplevel.c:790
> jl\_toplevel\_eval\_in at /home/\<snip\>/julia/src/toplevel.c:883
> eval at ./boot.jl:331
> exec\_options at ./client.jl:272
> \_start at ./client.jl:506
> jfptr\_\_start\_54721 at /home/\<snip\>/julia/usr/lib/julia/sys.so (unknown line)
> jl\_apply at /home/\<snip\>/julia/ui/../src/julia.h:1690 \[inlined\]
> true\_main at /home/\<snip\>/julia/ui/repl.c:106
> main at /home/\<snip\>/julia/ui/repl.c:227
> \_\_libc\_start\_main at /lib64/libc.so.6 (unknown line)
> \_start at ./julia/julia (unknown line)
> Allocations: 4879465 (Pool: 4878483; Big: 982); GC: 6
> Illegal instruction (core dumped)
> \`\`\`
> 
> The machine this specific crash was generated on looked like this:
> 
> \`\`\`
> Julia Version 1.5.1
> Commit 697e782ab8 (2020-08-25 20:08 UTC)
> Platform Info:
> OS: Linux (x86\_64-redhat-linux)
> CPU: Intel(R) Xeon(R) CPU E5-2430L v2 @ 2.40GHz
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-9.0.1 (ORCJIT, ivybridge)
> \`\`\`
> 
> but I could also create the crash on this:
> 
> \`\`\`
> Julia Version 1.5.0
> Commit 96786e22cc (2020-08-01 23:44 UTC)
> Platform Info:
> OS: Linux (x86\_64-linux-gnu)
> CPU: Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-9.0.1 (ORCJIT, skylake)
> Environment:
> JULIA\_NUM\_THREADS = 4
> \`\`\`
> 
> as well as this:
> 
> \`\`\`
> Julia Version 1.5.1
> Commit 697e782ab8 (2020-08-25 20:08 UTC)
> Platform Info:
> OS: Linux (x86\_64-redhat-linux)
> CPU: Intel(R) Xeon(R) CPU X5650 @ 2.67GHz
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-9.0.1 (ORCJIT, westmere)
> \`\`\`
> 
> but \_not\_ on this:
> 
> \`\`\`
> Julia Version 1.5.1
> Commit 697e782ab8 (2020-08-25 20:08 UTC)
> Platform Info:
> OS: Linux (x86\_64-pc-linux-gnu)
> CPU: Intel(R) Core(TM) i7-3667U CPU @ 2.00GHz
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libllvm-9.0.1 (ORCJIT, ivybridge)
> \`\`\`
> 
> , where the julia process never seemed to crash but instead seemed to be stuck in an infinite loop.
> 
> The command that was run was basically \`julia -e 'include("unreachablereached.jl"); while true; generate(Any); end'\` (in order to ensure that it crashed, at least at some point), but even just running \`generate(Any)\` with that file included seemed to result in an endless loop/crash.
> 
> The machine with the IvyBridge Xeon CPU also was helpful in that I could create an rr trace with it, but the first one I made was wrong so I'll make a new one.
> 
> Anyhow, I hope I'm not doing something monumentally stupid in my code, I'd really like it if this could work 😅
> 
> I haven't tested master yet, but I plan to do that next.

So if one doesn’t know how to construct a `T` and isn’t explicitly trying to fuzz a codebase, just generating a random “possibly valid” instance is going to lead to a lot of pain.

> [@foobar\_lv2](#):
>
> This is no worse or better than reinterpret or `Vector{T}(undef, 1)[1]`.

That’s true! To be clear, I think that is already pretty bad, and shouldn’t be made more likely by liberal use of `Expr(:new)`, making the `undef` problem an issue for all `T` and not “just” `Vector{T}` 🙂

> [@foobar\_lv2](#):
>
> But seriously, I think this is the only example where you get honest-to-god UB from badly initialized bitstypes?

It’s the best known one, but the example is representative for all invariant-breaking usages of `reinterpret`. At least the docstring of `reinterpret` warns about this problem now.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 23, 2024, 9:45pm UTC](https://discourse.julialang.org/t/default-constructor-for-any-type/110546/40 "2024-02-23T21:45:46Z")

</div>

> [@Sukera](#):
>
> No, you cannot assume that all primitive values have a `zero` OR a `one`. For example, the structs you can define through [FieldFlags.jl](https://discourse.julialang.org/t/ann-fieldflags-jl-bitfield-like-structs/100594) have no defined “default value”. They’re not even numeric at all, and don’t even have a zero initializer! There used to be one, but it caused some problems downstream precisely because assuming that all-zero is valid is not good.

I don’t happen to understand what the issue would be with initializing an all-zero `bitfield`, can you elaborate?

I wouldn’t expect all types to have a `zero` or a `one`, primitive or otherwise, the function constructor would need to check that.

And sure, there must be structs out there which throw errors from validation if called on default types when defined this way. A best-effort basis would create the default function, call it in a try block, and return an informative error if you can’t make a default for that type.

Crashing Julia by calling a constructor sounds like a bug, though. A bug in the current release of the runtime isn’t a good argument against writing a library like this, bugs get patched eventually. We hope.

It’s too much to expect for a default-constructed value to have up-to-any correct semantics, but I maintain that it’s tractable to write a default-constructor-constructor which either returns one or throws an error if it can’t.

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

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