# Primitive and Composite? Types

**URL:** <https://discourse.julialang.org/t/primitive-and-composite-types/19076>\
**Category:** New to Julia\
**Created:** [December 28, 2018, 8:41pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076 "2018-12-28T20:41:00Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![iwelch](https://avatars.discourse-cdn.com/v4/letter/i/8c91f0/32.png) [@iwelch](https://discourse.julialang.org/u/iwelch)\
**Post date:** [December 28, 2018, 8:41pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/1 "2018-12-28T20:41:00Z")

</div>

What is the opposite of a primitive type? Is it a composite type?

I am reading [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/index.html) . " [Composite types](https://en.wikipedia.org/wiki/Composite_data_type) are called records, structs, or objects in various languages."

Is an array composite or primitive?

(I am asking in order to accurately describe behavior when passed as argument to a function. Composite types have contents that can be assigned to, while primitive types do not?)

And what are Unions?

---

<div class="post-metadata">

**Author:** ![ninjaaron](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ninjaaron/32/6392_2.png) [@ninjaaron](https://discourse.julialang.org/u/ninjaaron)\
**Post date:** [December 28, 2018, 10:17pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/2 "2018-12-28T22:17:14Z")

</div>

For all practical purposes, primitives are numeric types of a fixed length, like Int64 (8 bytes), though they could theoretically be any fixed number of bytes to which a fixed meaning is assigned (Char is an example).

Composite types are types that contain any (predefined) number of other type instances. If you know any language with classes, classes are one form of a composite type (though classes do a lot more than simple data composition). Julia structs are not essential different from Julia’s tupels (except that they are distinguished by the compiler). They just give a formal name to and a way to dispatch on a certain collection of types bundled together.

Arrays in Julia are implemented in C and I haven’t looked at their implementation, but I have to assume they are composite types, since they contain information about their length and shape.

Arrays are conceptually a little different, however. In memory, they are more like a bunch of blocks of memory allocated to hold n number objects of a certain type. You can just think of them as a bunch of objects in a row, rather than one specific object unto themselves. In Julia, there is also some metadata tied to that row of objects.

Unions are a way to make something accept multiple types. Union{Int64,Float64} means that the either an Int64 or a Float64 could occur in that place. I mostly just use them to tell Julia that a type could be a specific type or `nothing`. (this is also a good case, since Julia can optimize for that, but a lot of other Union types are difficult to optimize.)

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [December 29, 2018, 1:15am UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/3 "2018-12-29T01:15:16Z")

</div>

According to the documentation of `isprimitivetype`, a type in Julia is primitive if it was declared using the `primitive` keyword. Composite types are created using either `struct` or `mutable` struct, and you can query this property using `isstructtype`.

> [@iwelch](#):
>
> Is an array composite or primitive?

`Array` is a bit of a special case, as it isn’t defined in Julia code but in C, so it doesn’t make sense to query whether it was ‘created using `struct`’. However,

```julia
julia> isprimitivetype(Vector{Float64})
false

```

and you can see the actual implementation of `isprimitivetype` and `isstructtype` here:

> <https://github.com/JuliaLang/julia/blob/002a9f5d76faa459dd6b9984b97410206aa055a6/base/reflection.jl#L384-L410>

---

<div class="post-metadata">

**Author:** ![iwelch](https://avatars.discourse-cdn.com/v4/letter/i/8c91f0/32.png) [@iwelch](https://discourse.julialang.org/u/iwelch)\
**Post date:** [December 29, 2018, 6:31pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/4 "2018-12-29T18:31:27Z")

</div>

thanks, aaron and twan.

[1] I am trying to organize my logic now in order to explain assignments and argument passing to functions to students and myself. I think I will need to explain something like a “container-type,” where assignments create aliases and not copies. Container types encompass arrays, structs, dicts, etc. does this make sense, or do I misunderstand something? Is there already a sanctioned name?

does julia has a built-in function to learn whether a type is a container type or not? presumably, I could write a function that could work by assigning a value to an instantiated alias, and seeing whether it affects the original. ugly but functional. or does this already exist?

[2] back to Unions. I think `Union{Float64,Missing}` is also pretty common (not just union with nothing). I failed to figure out how to create a non-vector union type scalar instance for experimenting (otherwise, pretty useless):

```julia
julia> xv= 2.0::Union{Float64, Missing}
2.0

julia> typeof(xv)
Float64

```

Thus I do not know how to experiment with whether this is internally a container or a non-container type.

It is _not_ a primitive type or an abstract type:

```julia
julia> isprimitivetype( Union{Float64, Missing} )
false

julia> isabstracttype( Union{Float64,Missing} )
false

```

Moreover, the docs says "A type union is a special abstract type which includes as objects all instances of any of its argument types, " and gives as an example a Union of a Float64 with Abstractstring, but this does not trigger the isabstracttype() function:

```julia
julia> isabstracttype( Union{Float64,Missing} )
false

julia> isabstracttype( Union{Float64,AbstractString} )
false

```

so, abstracttypes and unions are a bit confusing to me, too. is a union float-missing a primitive type or an abstract type or a … ?

/iaw

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [December 29, 2018, 8:16pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/5 "2018-12-29T20:16:38Z")

</div>

> [@iwelch](#):
>
> does julia has a built-in function to learn whether a type is a container type or not?

First we’d need a clear definition of what a container type is.

> [@iwelch](#):
>
> a “container-type,” where assignments create aliases and not copies.

What do you mean by assignment, exactly? Do you mean you want to test for the ability to assign a value to one of the fields of a composite type? You can do this for any `mutable struct`, and you can test for this property with `isimmutable` (which takes a _value_ as an argument, as opposed to `isprimitivetype` / `isstructtype`).

> [@iwelch](#):
>
> ```julia
> xv= 2.0::Union{Float64, Missing}
> 
> ```

This only asserts that the value `2.0` is either a `Float64` or a `Missing`. Since it’s a `Float64`, the type assertion passes. See [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#Type-Declarations-1) for more info.

It is not possible to construct a value that has a non-concrete type (test using `isconcretetype`). So it’s impossible to construct a value `xv` for which `typeof(xv)` returns a `Union` type, just like it’s impossible to construct a value of `AbstractFloat` type. But you _can_ create a composite type that is able to store concrete values of either `Float64` or `Missing` type, e.g.:

```julia
struct Foo
    xv::Union{Float64, Missing}
    # note: the `::Union{Float64, Missing}` is *not* a type assertion like before,
    # it's a specification of which values this field should be able to store
end

foo1 = Foo(missing) # works
foo2 = Foo(2.0) # works
foo3 = Foo("abc") # doesn't work

```

If you replace `struct` with `mutable struct` above, you’d also be able to assign values of either `Float64` or `Missing` type to the field `xv` after construction.

> [@iwelch](#):
>
> Moreover, the docs says "A type union is a special abstract type which includes as objects all instances of any of its argument types, " and gives as an example a Union of a Float64 with Abstractstring, but this does not trigger the isabstracttype() function:

> [@iwelch](#):
>
> is a union float-missing a primitive type or an abstract type or a …

I think either the documentation or `isabstracttype` should be changed. See also this TODO:

> <https://github.com/JuliaLang/julia/blob/121e814bfeec8ac0a45da2c4b5c87189366e1aec/base/reflection.jl#L510>

No union type is a primitive type (you can’t create a union type using the `primitive` keyword).

---

<div class="post-metadata">

**Author:** ![iwelch](https://avatars.discourse-cdn.com/v4/letter/i/8c91f0/32.png) [@iwelch](https://discourse.julialang.org/u/iwelch)\
**Post date:** [December 29, 2018, 10:33pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/6 "2018-12-29T22:33:52Z")

</div>

> [@tkoolen](#):
>
> What do you mean by assignment, exactly? Do you mean you want to test for the ability to assign a value to one of the fields of a composite type?

No. I mean an object where assignment creates an alias (a second pointer to the same contents). If the object supports ‘.=’, it is a container type, so struct and array qualify. So does Dict:

```julia
julia> adict= Dict{String,Int64}("O" => 1, "T" => 2); bdict=adict; bdict["O"]=99; adict
Dict{String,Int64} with 2 entries:
  "T" => 2
  "O" => 99

```

Same for arrays. but of course for scalars,

```julia
julia> ascalar= 12; bscalar= ascalar; bscalar= 99; ascalar
12

```

If the scalar contents had been stored at a pointed-to destination (like an array, dict, struct, etc.), then ascalar would also have turned into 99. (Still thinking in C, I mean the difference between an object which is internally stored as a pointer to the actual content, vs an object where we store the content and not a pointer.)

* * *

Incidentally, why don’t we call it a struct rather than a composite? are there other composites than stucts?

* * *

I can not only create a `struct a::Union{Float64,Missing}; end`, I can also create an array of `Vector{ Union{Float64,Missing}}`. I now understand that I cannot create a scalar with this type. This obviates my question about whether a union is primitive or not.

now, an array seems to be a sequential bitpattern (in C), plus some header info. why does it not take more space to store a Union array if it is not simple bit-patterns? how does Julia internally store Unions?

```julia
julia> typeof( Vector{Float64}( [1.0, 3.0, 2.0] ) )
Array{Float64,1}

julia> sizeof( Vector{Float64}( [1.0, 3.0, 2.0] ) )
24

julia> typeof( Vector{Union{Float64,Missing}}( [1.0, 3.0, 2.0] ) )
Array{Union{Missing, Float64},1}

julia> sizeof( Vector{Union{Float64,Missing}}( [1.0, 3.0, 2.0] ) )
24

```

---

<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 29, 2018, 11:07pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/7 "2018-12-29T23:07:15Z")

</div>

> [@iwelch](#):
>
> julia\> ascalar= 12; bscalar= ascalar; bscalar= 99; ascalar  
> 12
> 
> If the scalar contents had been stored at a pointed-to destination (like an array, dict, struct, etc.), then ascalar would also have turned into 99.

Not so–assignment _never_ changes any object. It just attaches a label to some existing value:

```julia
julia> a = [12]; b = a; b = [99]; a
1-element Array{Int64,1}:
 12

```

The fact that the label `b` was previously attached to the same value as `a` is of no consequence.

Of course, `b .= [99]` does mutate `a` as well, but that’s not assignment. Instead, it is roughly equivalent to: `broadcast!(b, identity, [99])`, which mutates the value to which the label `b` is attached. If that value is the same value to which the label `a` was attached, then you will see the same modification to `a`.

This gets to one of the nicest points about Julia (as opposed to, say, C++), which is that assignments and function arguments always work in the same way for every value. While the compiler _may_ copy values passed into functions, it will only do so for completely immutable values, so there is no practical reason to worry about whether a copy has happened or not. Thus you can write your code without having to worry about whether a value might accidentally be copied. Likewise, there is no need to worry about whether `a = b` creates an “alias” or a “copy” depending on the types of `a` or `b`. All assignments behave in exactly the same way: attaching a label to a value, nothing more.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [December 29, 2018, 11:46pm UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/8 "2018-12-29T23:46:29Z")

</div>

> [@iwelch](#):
>
> Incidentally, why don’t we call it a struct rather than a composite? are there other composites than stucts?

I’m also a proponent of “same thing, same name”, but I can think of two reasons for calling them composite types in the documentation:

1. to anchor to a common term in programming languages in general
2. the `type` → `mutable struct` and `immutable type` → `struct` renames happened not that long ago; maybe the documentation stems from before this rename.

> [@iwelch](#):
>
> now, an array seems to be a sequential bitpattern (in C), plus some header info. why does it not take more space to store a Union array if it is not simple bit-patterns? how does Julia internally store Unions?

See [isbits Union Optimizations · The Julia Language](https://docs.julialang.org/en/v1/devdocs/isbitsunionarrays/#isbits-Union-Arrays-1).

I think you need `Base.summarysize` instead of `sizeof` for this purpose:

```julia
julia> Base.summarysize([1.0])
48

julia> Base.summarysize(Union{Float64, Missing}[1.0])
56

```

I’m actually not sure why it was decided not to include the size of the type tag array (and the header?) in `sizeof(::Array)`.

---

<div class="post-metadata">

**Author:** ![iwelch](https://avatars.discourse-cdn.com/v4/letter/i/8c91f0/32.png) [@iwelch](https://discourse.julialang.org/u/iwelch)\
**Post date:** [December 30, 2018, 4:03am UTC](https://discourse.julialang.org/t/primitive-and-composite-types/19076/9 "2018-12-30T04:03:30Z")

</div>

thank you, everyone. I am getting to be clearer. yes, it seems that the inconsistency is in C, not in Julia; and I have lived with C for so long that my first reaction was that C is the consistent language…

It would have been less confusing if julia had used the word ‘composite’ as the keyword, or ‘struct’ as in its docs. maybe some day…
