# Syntax for putting constraints on type

**URL:** https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588
**Category:** New to Julia
**Tags:** type, parametric-types
**Created:** [April 17, 2022, 3:28am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588 "2022-04-17T03:28:53Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 17, 2022, 3:28am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/1 "2022-04-17T03:28:53Z")

</div>

I listed the syntax for putting constraints on types at different places, such as method, struct. Please let me know whether this is correct.

# parametric type:

- Vector{\<:Real}
- Vector{T} where T \<: Real

# method

- function f(x::T) where {T\<:Real}
- function f(x::T where T\<:Real)

# struct

- struct S{T\<:Real}
- where is not an option

I just feel it is a little bit inconsistent, so just listed out to check whether my understanding is correct.

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [April 17, 2022, 6:29am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/2 "2022-04-17T06:29:20Z")

</div>

For methods, you are missing the simplest one: `function f(x::Real)`

---

<div class="post-metadata">

### Author: ![FrancisKing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisking/32/24966_2.png) [@FrancisKing](https://discourse.julialang.org/u/FrancisKing)
#### Post date: [April 17, 2022, 7:12am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/3 "2022-04-17T07:12:40Z")

</div>

> [@sychen52](#):
>
> I just feel it is a little bit inconsistent

Many languages have these inconsistencies. It goes with the territory.

---

<div class="post-metadata">

### Author: ![FrancisKing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisking/32/24966_2.png) [@FrancisKing](https://discourse.julialang.org/u/FrancisKing)
#### Post date: [April 17, 2022, 7:15am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/4 "2022-04-17T07:15:25Z")

</div>

> [@gdalle](#):
>
> For methods, you are missing the simplest one: `function f(x::Real)`

Naively, I would expect `x::Real` to be slower than `x::T where T<:Real`. The first one requires work to determine what sort of value it is, the second one uses concrete type `T`.

---

<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: [April 17, 2022, 7:27am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/5 "2022-04-17T07:27:35Z")

</div>

> [@FrancisKing](#):
>
> Naively, I would expect `x::Real` to be slower than `x::T where T<:Real` . The first one requires work to determine what sort of value it is, the second one uses concrete type `T` .

They’re exactly the same - both have to figure out which type the object is to specialize the function during compilation. The latter just allows you to use `T` (i.e. the actual type) in your function as well, if you require it.

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [April 17, 2022, 1:29pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/6 "2022-04-17T13:29:57Z")

</div>

Besides, in this case `T` doesn’t have to be a concrete type, it can be abstract as well  
EDIT: this is wrong, see below

---

<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: [April 17, 2022, 1:34pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/7 "2022-04-17T13:34:14Z")

</div>

No. `T` will always be a concrete type, as that’s the only thing an object can have at runtime. `abstract` or `Union` types are only relevant for inference and dispatch, in a method it will be concrete.

The only time such a `T` can be non-concrete is when you explicitly pass that in via an already non-concrete type parameter, like here:

> **Old example with \`Type\`**
>
> ```julia
> julia> f(::Type{T}) where T = T
> f (generic function with 1 method)
> 
> julia> f(Type{Integer})
> Type{Integer}
> 
> ```

```julia
julia> f(::Vector{T}) where T = T
f (generic function with 1 method)

julia> f(Integer[])
Integer

```

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 17, 2022, 1:47pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/8 "2022-04-17T13:47:13Z")

</div>

You could have used `Vector` for this example, `Type` is kinda special and may confuse readers.

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [April 17, 2022, 2:10pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/9 "2022-04-17T14:10:37Z")

</div>

My bad, today I learned!

---

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 17, 2022, 9:33pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/10 "2022-04-17T21:33:09Z")

</div>

Another thing that feels tricky to me is that:  
It is considered good/okay to use abstract type in function arguments. As @Sukera mentioned, a version of the method specialized to the type you actually used is created and compiled when you call the function.  
However, it is considered bad when using abstract types in the fields of a struct. I just read it yesterday on the Performance tips page. It says if it is a mutable struct, the field with abstract type can change its type at runtime. However, I was a little bit surprised that for immutable structs, the compiler cannot do something like it does for method with abstract type.

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [April 17, 2022, 10:08pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/11 "2022-04-17T22:08:12Z")

</div>

It could, but allowing the two distinct behaviors allows you to ask for specialization or non-specialization, which is a useful distinction.

---

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 17, 2022, 10:33pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/12 "2022-04-17T22:33:14Z")

</div>

On second thought, maybe I was wrong.

- For the following example, in `S{Int64}`, and `s.a` could be `Vector{Int64}` or `SparseVector{Int64}`. As a result, `S{Int64}` is like an abstract type itself. Imagine if you put it into a Vector, `Vector{S{Int64}}` is like `Vector{AbstractVector{Int64}}`. The memory layout of each `AbstractVector{Int64}` can be very different (for example, some are all on the stack, some are all on the heap.). Therefore, it is hard to optimize. Is that right?

```julia
struct S{T}
    a::AbstractVector{T}
end

```

One more question, when you say specialization or non-specialization, is the example above non-specialization and the example below specialization:

```julia
struct S{T<:AbstractVector}
    a::T
end

```

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 17, 2022, 11:25pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/13 "2022-04-17T23:25:26Z")

</div>

> [@sychen52](#):
>
> As a result, `S{Int64}` is like an abstract type itself.

Imprecise, depends on what you mean by “like”. `S{Int64}` is a concrete type. A concrete type that has a _boxed_ field (or an abstract type field, if you prefer calling it that way), i.e., a field that may store different concrete types.

> [@sychen52](#):
>
> The memory layout of each `AbstractVector{Int64}` can be very different (for example, some are all on the stack, some are all on the heap.). Therefore, it is hard to optimize. Is that right?

I believe that is not the case. Ever `S{Int}` will gave the same layout, a single boxed field (basically a `void*` pointer), and every `S{Int}` will store what is inside field `a` in the heap.

> [@sychen52](#):
>
> One more question, when you say specialization or non-specialization, is the example above non-specialization and the example below specialization

I may be wrong, but I think that what @StefanKarpinski referred to is a special behavior just for methods. See: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing)

---

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 18, 2022, 5:19am UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/14 "2022-04-18T05:19:07Z")

</div>

I used to think StaticArray, which is a subtype of AbstractArray, is stack-allocated. However, After reading [this](https://discourse.julialang.org/t/staticarrays-and-allocations/62123/20), I realize Julia does not guarantee either stack or heap allocation.  
But I feel it is also not guaranteed to be on the heap as you mentioned.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 18, 2022, 2:06pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/15 "2022-04-18T14:06:50Z")

</div>

There is no way Julia can guarantee every instance of a `Type` is either stack allocated or heap allocated, this is just not how things work.

The exact rules are hard to lay out but, for example, a `Vector{SVector{Int, 3}}` will have each `SVector{Int, 3}` unboxed and contiguous in memory (basically, the layout will be the same as a `Vector{Int}` three times the size), but this will be heap memory; because unless the compiler is able to do some very aggressive optimization all memory of any `Vector` ends is from the heap, independently from its size or the type of the objects inside it. If it wasn’t in the heap, the `Vector` could not be dynamic in size, because the stack works exactly as it says, it is a stack, the moment you define other object that goes in the stack it starts immediately after the last object has ended, and resizing the `Vector` would overwrite variables defined in the same scope with garbage (you can actually do this in `C`, by defining a static-size array in the stack but writing after its end onto other variables of the scope). This is the reason the StaticArrays variants can end up in the stack, they do not have dynamic length, however, they will often end up in the stack only if they are not attributed to a region of memory that is not already guaranteed to be in the heap, like inside a `Vector`.

The explanation is messier than I do like, but I hope it helps. Any questions just ask.

---

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 18, 2022, 2:31pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/16 "2022-04-18T14:31:14Z")

</div>

Thanks. That is very helpful. I think you are saying:

1. A user-defined subtype of AbstractArray may be stack-allocated, such as StaticArray.
2. A `Vector{T}` will be heap-allocated no matter what that `T` is, “unless the compiler is able to do some very aggressive optimization”
3. An example of this “very aggressive optimization” may happen if the compiler realizes the `Vector` is small and never change its size, but I guess this is just a necessary condition and not sufficient.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 18, 2022, 5:32pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/17 "2022-04-18T17:32:06Z")

</div>

Yes, it is more or less what you pointed out. It is more complex in practice, and I will point out some of these subtleties but they are not necessary to understand in general:

1. Everything that is allocated in the heap in fact is often allocated both in _the stack and the heap_. For example, `Vector{T}` has **its contents** always in the heap, but the pointer to where in the heap it is and its size may be in the stack. This happens because the pointer itself and the Int storing the size are of fixed size, and if the `Vector{T}` does not escape the current scope (i.e., it is not passed to a non-inlined function nor is returned) then these info can be stored in the stack. If the `Vector{T}` is stored in the heap itself (not just its contents), then you have in the stack just the pointer to the pointer+length block which then points to the contents, i.e., a double indirection.
2. When `Vector{SArray{Int, 3}}` has its content (the `SArray`s) in the heap, they are inlined and contiguous, so even being in the heap is not that bad. The problem happens if it was a `Vector{Vector{Int}}` instead, for example, then what would be contiguous inside the outer vector is either the single pointers to the pointer+length blocks, or the pointer+length block themselves. This means already 3~4 layers of indirection, and this is one thing that starts slowing the code, because now accessing `x[1][1]` may mean to access the pointer `x` that leads to the pointer+length block of `x` and from it get the position of `x[1]` that contains just a pointer that you follow to the pointer+length block of `x[1]` and now you can finally follow that last pointer to know where is `x[1][1]` stored and fetch it. If the outer vector does not escape the scope and has `SVector{Int}` inside it, then the only indirection is the pointer+length block of `x` and the second index just offset the position in the same block of memory (all `SVector` contents are contiguously stored directly into the `x` block of memory, instead of pointers to the `SVector`s).

It is confusing, I know. Often pointers is where computer sci students start having problems.

---

<div class="post-metadata">

### Author: ![sychen52](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sychen52/32/34072_2.png) [@sychen52](https://discourse.julialang.org/u/sychen52)
#### Post date: [April 18, 2022, 8:32pm UTC](https://discourse.julialang.org/t/syntax-for-putting-constraints-on-type/79588/18 "2022-04-18T20:32:41Z")

</div>

Thank you for the example. That is helpful!
