# 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:** 1
**Showing post:** 39

<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.

---

_[View the full topic](https://discourse.julialang.org/t/default-constructor-for-any-type/110546)._
