āundefined behaviorā in C is quite a different thing from what people in this thread seem to think. C is a language with a standard, which defines certain things to behave in a certain way. In the particular case of reading from some allocated memory, as far as Iām aware, the standard only defines what should happen for initialized memory. It doesnāt say anything about what should happen if the memory is uninitialized, and hence these sorts of things are commonly referred to as āundefined behaviorā (because itās not defined in the C standard).
To be more accurate, it ought to be referred to as āinplementation (of the C compiler) dependent behaviorā, because any given compiler is free to define any semantics for āundefined behaviorā it wants, because any resulting implementation still conforms to the C standard.
In the terms of julia, this doesnāt really mean much at all - julia doesnāt have a standard, so there isnāt any defined behavior in the first place - in a sense, the implementation of the julia compiler currently in the repo on github is the standard.
What does this imply for undef
and arrays āinitializedā to that? Well, thereās multiple points there, depending on the element type of the array - for mutable/non-isbits types, you get an array filled with the special #undef
values, because you need some value to signify that there isnāt any valid instance at that index in the array (yet). The language also actually prevents you from trying to retrieve such an #undef
āvalueā - it must, because there isnāt anything there to retrieve.
For immutable isbitstype
s, the story is a bit different, because they donāt have any pointers inside of them - they are solely defined by their bitpattern. For some types, e.g. Int
or Float64
, all possible bitpatterns have a valid interpretation. For some others, e.g. a type wrapping an even integer, not all bitpatterns are valid instances, but which exactly are valid depends on the type in question. Generally, it would be preferrable to always construct arrays with valid instances, but that either means having a known sentinel value for each type that can be used for this (also known as the ābillion dollar mistakeā), force users to allocate arrays exclusively via something like fill
, taking a function that constructs each instance, or accept that Vector{T}(undef, ...)
is a low level tool thatās a bit dangerous to use. Whether reading from such an array is undefined behavior or not is beside the point - you get some bitpattern back, thereās just no guarantee that it observed the checks that might have been used in a proper construction of objects of that type. So from my POV, if anything, assuming that the objects of an uninitialized array are valid instances and that you can use them is unsafe (and perhaps undefined in the context of that type - but certainly not undefined in terms of julia as a whole, because you do get some bitpattern back, itās just not guaranteed to be valid for your type).
Most importantly though, no matter if this instance is āundefined behaviorā or not - the compiler is certainly not allowed to do whatever it wants when it encounters āundefined behaviorā (insofar that even exists in julia). That would be quite a bit crazy.