# Any at UnitRange seems unoptimal

**URL:** <https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650>\
**Category:** Internals & Design\
**Tags:** unitrange\
**Created:** [October 13, 2022, 9:05am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650 "2022-10-13T09:05:38Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 9:05am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/1 "2022-10-13T09:05:38Z")

</div>

Hey Julianners!

One of the most used struct `UnitRange`.  
I feel something is odd here. Why we have `Any[Core.Const(1), Int64]`? This sounds pretty unoptimal.

```julia
using InteractiveUtils
unitrange_any(N) = begin
	c=1:N
end

unitrange_any(6)
@code_warntype unitrange_any(6)

```

```julia
MethodInstance for unitrange_any(::Int64)
  from unitrange_any(N) in Main at /home/hm/repo/agei/tests/playground/core.partialstruct.jl:2
Arguments
  #self#::Core.Const(unitrange_any)
  N::Int64
Locals
  c::UnitRange{Int64}
Body::UnitRange{Int64}
1 ─ %1 = (1:N)::Core.PartialStruct(UnitRange{Int64}, Any[Core.Const(1), Int64])
│ (c = %1)
└── return %1

```

Shouldn’t we use `Tuple{Core.Const, DataType}`? Or due to `Core.Const(1)` the number 1 cannot be represented enough well and we would lose some performance due to lack of optimisation for that case?  
So why we use `Any[]` arrays? (I know the two type differs… but this is the case when we should use Tuple where it can keep all of it.

Specifically for `UnitRange` we know that, there will be about 1 or 2 parameter so Tuple should be pretty straightforward for me.

---

<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:** [October 13, 2022, 9:36am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/2 "2022-10-13T09:36:51Z")

</div>

`Core.PartialStruct` is not a special construct for `UnitRange` - it’s used in lots of different cases. If it would use a `Tuple` internally, code using it in the compiler would have to be recompiled for different instances. So using a `Vector{Any}` here is a hidden optimization in terms of compile time for the general case.

It’s also not related to anything happening at runtime here.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 9:39am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/3 "2022-10-13T09:39:14Z")

</div>

I think Vector{Any} won’t recompile as actually there is nothing to optimise when the internals are Any. 😃

But taking it seriously, I have to modify the question and throw the noise of PartialStruct away, it isn’t the point here indeed. (I will modify the question, so the function name is `unitrange_any` from now.)

---

<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:** [October 13, 2022, 9:50am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/4 "2022-10-13T09:50:19Z")

</div>

The reason you get a `Core.PartialStruct` in your output in the first place is because `@code_warntype` does not propagate the `6`, only that it’s an `Int`, which is sufficient to infer the return type of `UnitRane{Int64}`. This is not sufficient to create a full `UnitRange` object though, and thus `Core.PartialStruct` is created to at least be able to propagate the hardcoded `1` part. So there’s nothing unoptimal about this here.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 9:58am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/5 "2022-10-13T09:58:15Z")

</div>

So, I totally understand why ther is PartialStruct there. I am not talking about weather it can generate the function knowing the 6.  
The question is: “Why do we have Array: (`Any[Core.Const(1), Int64]`) instead of Tuple: (`(Core.Const(1), Int64)`), which looks much better from the compiler side?”

---

<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:** [October 13, 2022, 10:09am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/6 "2022-10-13T10:09:32Z")

</div>

Because it’s not better from the compiler side. Since a tuple has the types of its elements as part of its own type, any code accessing this would then need to be specialized for that tuple type, leading to lots and lots of recompilation of functions internal to the compiler. You could of course only compile one version for `Tuple` without specializing on the element types, but that is no better than `Vector{Any}`, which is much more convenient to work with in terms of adding & removing elements.

Again, using `Vector{Any}` here is an optimization. `Core.PartialStruct` may be used for lots of other things, which can contain a number of different types. Avoiding multiple code paths _inside the compiler_ is advantageous in terms of the amount of compile time happening.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 11:58am UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/7 "2022-10-13T11:58:55Z")

</div>

You are basically stating, it is better to drop the type information and compile it with Any, so we can spare compilation time.

LLVM can build like 250 time faster code with type information… This sounds really bad idea from my opinion.

Also like 99.9% of the case in my code I use Core.Const(1), Int64 and it would be like so for others in general. So I wouldn’t even bother with that 0.1% if I could make sure I get the optimisation perfectly.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [October 13, 2022, 12:38pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/8 "2022-10-13T12:38:52Z")

</div>

The `Vector{Any}` only exists at compile time, for use by the compiler. LLVM knows all types at compile time here. You can take a look at the `@code_llvm` if it helps.

---

<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:** [October 13, 2022, 1:14pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/9 "2022-10-13T13:14:56Z")

</div>

> [@Marcell\_Havlik](#):
>
> You are basically stating, it is better to drop the type information and compile it with Any, so we can spare compilation time.

I’m saying that we compile `Core.PartialStruct` and the functions _inside the compiler_ with `Vector{Any}`. I’m NOT saying that your user code will compile with `Vector{Any}`. Those are two very different things. That’s also why I pointed out that seeing the `Core.PartialStruct` here in the first place is misleading, because it’s not something that’s actually relevant for your `unitrange_any`, either in terms of runtime performance or in terms of compile time (and in fact helps make compile time faster, due to not having to recompile the compiler itself, which would be required if that were a `Tuple`).

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 1:21pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/10 "2022-10-13T13:21:58Z")

</div>

Then the question remains.  
Doesn’t that `Any[Core.Const(1), Int64]` cause run time slow downs on the long run? (I don’t want to spare compilation time on my performant code in most of the cases.)

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 1:24pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/11 "2022-10-13T13:24:39Z")

</div>

Actually it is impossible to know for the llvm. So I am not sure. `[Core.Const(1), Int64]` is an ambigious type, that is why it is Any.

---

<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:** [October 13, 2022, 1:33pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/12 "2022-10-13T13:33:37Z")

</div>

> [@Marcell\_Havlik](#):
>
> Doesn’t that `Any[Core.Const(1), Int64]` cause run time slow downs on the long run?

No. That array does not exist at runtime, only during compilation, inside the compiler. It does not exist in your user code.

> [@Marcell\_Havlik](#):
>
> (I don’t want to spare compilation time on my performant code in most of the cases.)

Using `Tuple` here instead would NOT increase performance at run time, it would only increase the duration taken to compile your code. As such, `Vector{Any}` here is an optimization to have faster compilation in general, WITHOUT impacting runtime performance.

> [@Marcell\_Havlik](#):
>
> Actually it is impossible to know for the llvm. So I am not sure. `[Core.Const(1), Int64]` is an ambigious type, that is why it is Any.

What Chris was trying to say is that this array does not exist when your `unitrange_any` function ultimately runs. That array only exists during _compilation_, not when your function is executing.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 2:26pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/13 "2022-10-13T14:26:59Z")

</div>

So basically the compiler knows the type of the array[1] and array[2] even if we “deleted” the type by addressing into a heterogeous array?  
I was always using tuples in my code in these scenarios as I saw it keep the type and the type is known at compile time.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 2:28pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/14 "2022-10-13T14:28:32Z")

</div>

Ok… I am already too much I know! But I just had to test what you said.

It says it just doesn’t quess the type if the array is heterogenous.  
Please help me out what do I do wrong and how does it know the type later on?

```julia
using InteractiveUtils
heterogen_arr_type_stability(x) = begin
  x[2]
end

@code_warntype heterogen_arr_type_stability([Core.Const(2), 6])

```

Res:

```julia
MethodInstance for heterogen_arr_type_stability(::Vector{Any})
  from heterogen_arr_type_stability(x) in Main at /home/hm/repo/agei/tests/playground/core.partialstruct.jl:13
Arguments
  #self#::Core.Const(heterogen_arr_type_stability)
  x::Vector{Any}
Body::Any
1 ─ %1 = Base.getindex(x, 2)::Any
└── return %1

```

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 2:38pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/15 "2022-10-13T14:38:57Z")

</div>

Sidenote: I just wanted to check how does it work?  
`@edit Core.PartialStruct(UnitRange{Int64}(1,3), Any[Core.Const(1), Int64])`  
res:  
`PartialStruct(@nospecialize(typ), fields::Array{Any, 1}) = $(Expr(:new, :PartialStruct, :typ, :fields))`  
cant we use `@nospecialize` to don’t specialize on that type and use tuple? So we could remove billions of Any from everyones code without any serious change? I know I am beginner at julia core… so sorry for the beginner question.

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [October 13, 2022, 2:40pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/16 "2022-10-13T14:40:04Z")

</div>

I don’t think the claim ever was that it could infer the type from the `Any` array (though I should say I don’t know what I’m talking about, just reading the posts here), but that array just contains information for the compiler to generate code. More precisely the array seems to contain the types that the `UnitRange` should be compiled for (`Core.Const(1)` and `Int64`) which can be used in the compiler to generate code for this case. Here the case is that you have a constant 1 as the start and an `Int64` as the end, which are then used by the compiler to generate fast code based on those types.

---

<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:** [October 13, 2022, 2:40pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/17 "2022-10-13T14:40:31Z")

</div>

> [@Marcell\_Havlik](#):
>
> So basically the compiler knows the type of the array[1] and array[2] even if we “deleted” the type by addressing into a heterogeous array?

Every element in an `Vector{Any}` has its own type bundled at runtime. No type is ever “deleted”.

> [@Marcell\_Havlik](#):
>
> I was always using tuples in my code in these scenarios as I saw it keep the type and the type is known at compile time.

That’s a different scenario. The `Vector{Any}` you’re seeing as part of the `Core.PartialStruct` is an object _internal to the compiler_, where this is intended. When you swap that object to a `Tuple` instead, the compiler has to recompile its own internal functions it uses for _compilation_. This is what using `Vector{Any}` saves us from here. I’m not talking about your user function.

> [@Marcell\_Havlik](#):
>
> It says it just doesn’t quess the type if the array is heterogenous.  
> Please help me out what do I do wrong and how does it know the type later on?

That is perfectly fine and correct. As I said, in a `Vector{Any}`, every object has its type bundled with its data, a so-called type tag. But again, what you’re observing in the `Core.PartialStruct` has _nothing to do with your code_. It’s a measure done so that _compiler internals_ don’t have to recompile themselves while compiling your function.

---

<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:** [October 13, 2022, 2:55pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/18 "2022-10-13T14:55:23Z")

</div>

> [@Marcell\_Havlik](#):
>
> So we could remove billions of Any from everyones code without any serious change?

No - again, there is no place in your `unitrange_any` where only `Any` could be inferred. The `Vector{Any}` and the `Core.PartialStruct` are a compiler artifact. It is not related to your specific user code (or any type stable user code for that matter). No `Core.PartialStruct` object will be created for your `unitrange_any` at runtime, because when you actually call `unitrange_any` with a value, everything exists so that the `UnitRange` object can be created like any other object. `Core.PartialStruct` is just a compiler optimization to allow _some_ additional type propagation during inference. It is not related to any runtime object coming into existence or being allocated.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [October 13, 2022, 3:09pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/19 "2022-10-13T15:09:00Z")

</div>

Ok, I was checking my `@code_warntype` where there were like 50-60 `Core.PartialStruct` in one function and that `Any[...]` was really disturbing as why it wasn’t `Tuple`… but ok. I of course understand these.

After all these discussion, I understand there is no performance improvement, for me `Tuple` with `@nospecialize` is just a nicer way and could avoid the `Any[]` from the process while keeping all the things in the same way. But you can demolish this idea too if you think we would lose something with that `Tuple` thing. 😃

---

<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:** [October 13, 2022, 3:21pm UTC](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650/20 "2022-10-13T15:21:30Z")

</div>

> [@Marcell\_Havlik](#):
>
> Ok, I was checking my `@code_warntype` where there were like 50-60 `Core.PartialStruct` in one function and that `Any[...]` was really disturbing as why it wasn’t `Tuple`… but ok. I of course understand these.

`Tuple` is not a magic “go-fast” switch - else it would of course be used everywhere 🙂 It can for example be very bad for performance when there’s lots of different tuples that need to be handled, as is the case in the compiler. You have to remember that each combination of tuple elements is its own type, and (oversimplifying) having to compile a new compiler for each kind of `Core.PartialStruct` whenever a new one is encountered is really bad for performance of the compiler. Keep in mind that the compile time of your function is the _run time_ of the compiler. So having to compile in the compiler is bad for the compile time of your function.

If you share the code you encountered `PartialStruct` in, I can try to explain why you see it there.

[Next page](https://discourse.julialang.org/t/any-at-unitrange-seems-unoptimal/88650.md?page=2)
