# How to omit type assertion from compiled output

**URL:** <https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090>\
**Category:** General Usage\
**Tags:** question\
**Created:** [April 29, 2023, 3:13pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090 "2023-04-29T15:13:04Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ColinCaine](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/colincaine/32/7211_2.png) [@ColinCaine](https://discourse.julialang.org/u/ColinCaine)\
**Post date:** [April 29, 2023, 3:13pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/1 "2023-04-29T15:13:05Z")

</div>

Hello!

I have a struct `S` that contains a `Union{Some{String}, Nothing}` and I’m accessing the value at a time when it’s guaranteed to be a `Some{String}` (unless someone accesses the private fields of the struct). Can I access the wrapped String value without Julia emitting code for a type assertion?

Concrete example that already includes an assert:

```julia
struct S1
    v::Union{Some{String}, Nothing}

    S1() = new(Some("foo"))
end

function f1(s::S1)
    # By the time this function executes, v is guaranteed to contain a value
    # of type `Some{String}`.
    @assert typeof(s.v) == Some{String}
    return something(s.v)
end

# The challenge is to make Julia emit some code that doesn't contain any
# error handling for the case where v is `nothing`.
@code_llvm f1(S1())

```

Harder mode that’s closer to my real problem:

```julia
struct S2
    v::Vector{Union{Some{String}, Nothing}}

    S2() = new([Some("foo")])
end

function f2(s::S2)
    # By the time this function executes, v[1] is guaranteed to contain a value
    # of type `Some{String}`.
    v1 = @inbounds s.v[1]
    @assert typeof(v1) == Some{String}
    return something(v1)
end

# The challenge is to make Julia emit some code that doesn't contain any
# error handling for the cases where v[1] is `nothing` or out of bounds.
@code_llvm f2(S2())

```

I’m mostly asking out of curiosity, but if it is possible to omit these checks then I might be able to speed up a data structure I’ve written (though I won’t know until I do it whether the speed up will be worth the extra risk).

Thanks!

---

<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 29, 2023, 4:19pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/2 "2023-04-29T16:19:22Z")

</div>

I think the type assertion could also look like this:

```julia
struct S1
    v::Union{Some{String}, Nothing}

    S1() = new(Some("foo"))
end

function f1(s::S1)
    # By the time this function executes, v is guaranteed to contain a value
    # of type `Some{String}`.
    v::Some{String} = s.v
    return something(v)
end

```

However I don’t know if the generated code solves your problem or not

---

<div class="post-metadata">

**Author:** ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)\
**Post date:** [April 29, 2023, 4:23pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/3 "2023-04-29T16:23:12Z")

</div>

I don’t know the answer, but AFAIK `@assert` is only for “debugging” purposes, and it is possible that it is optimized away. [Link to `@assert` docs](https://docs.julialang.org/en/v1/base/base/#Base.@assert). Based on that, I don’t think that it should be used for the purpose that you want to achieve.

---

<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 29, 2023, 5:16pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/4 "2023-04-29T17:16:38Z")

</div>

Fundamentally, the field is only known to be a union, so at least the field access itself infers as that union. Any further optimization then depends on the assignments like `v::Some{String} = s.v`, which do `v = convert(Some{String}, s.v)` in the actual code, to not throw an error at runtime, because `s.v` is only known as the union - it can’t really be eliminated.

So - what can be done? You can try using [SumTypes.jl](https://github.com/MasonProtter/SumTypes.jl), which tend to emit a bit better code, but you’re not going to get rid of the type instability completely.

---

<div class="post-metadata">

**Author:** ![ColinCaine](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/colincaine/32/7211_2.png) [@ColinCaine](https://discourse.julialang.org/u/ColinCaine)\
**Post date:** [April 29, 2023, 6:17pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/5 "2023-04-29T18:17:42Z")

</div>

Thanks all. I know why the compiler won’t emit better code by default, I’m looking for a mechanism for making the compiler believe something it can’t prove.

Thanks for the link to SumTypes.jl, the readme is interesting.

Regarding assert, I’m using it both to demonstrate how this can be solved in some other languages (tell the compiler a fact with an assert or typeassert, then compile with no runtime asserts) and because the Julia compiler seems to respond to the presence of asserts (adding an assert can speed your code up sometimes).

---

<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 29, 2023, 7:38pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/6 "2023-04-29T19:38:09Z")

</div>

The julia compiler does not, to my knowledge, handle `@assert` specially in any way. If you have a benchmark showing otherwise, I’d be willing to bet it’s the conditional check in the macro use, not the `@assert`, that could help the compiler.

---

<div class="post-metadata">

**Author:** ![ColinCaine](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/colincaine/32/7211_2.png) [@ColinCaine](https://discourse.julialang.org/u/ColinCaine)\
**Post date:** [April 29, 2023, 7:41pm UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/7 "2023-04-29T19:41:52Z")

</div>

That’s probably correct. I think the same behaviour occurs with any early termination (so throwing any error or returning early). The important thing is that the compiler seems to use the assertion condition (or the `if` condition from another early termination) to sometimes prove things that let it make optimisations.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 30, 2023, 12:31am UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/8 "2023-04-30T00:31:50Z")

</div>

From [Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#Base.@assert) :

> An assert might be disabled at various optimization levels. Assert should therefore only be used as a debugging tool and not used for authentication verification (e.g., verifying passwords), nor should side effects needed for the function to work correctly be used inside of asserts.

This suggests that there may be some optimization level that may omit an assertion.

One obvious case, is if the compiler thinks your assertion will always be true. It might not actually check if that is the case.

```julia
julia> f() = @assert true
f (generic function with 1 method)

julia> @code_llvm f()
; @ REPL[8]:1 within `f`
define void @julia_f_147() #0 {
top:
  ret void
}

```

One case where the compiler may assume wrongly is when you change constants in the REPL.

```julia
julia> const maybe = true
true

julia> g() = @assert maybe "Hello world"
g (generic function with 1 method)

julia> g()

julia> maybe = false
WARNING: redefinition of constant maybe. This may fail, cause incorrect answers, or produce other errors.
false

julia> g()

julia> g() = @assert maybe "Hello world"
g (generic function with 1 method)

julia> g()
ERROR: AssertionError: Hello world
Stacktrace:
 [1] g()
   @ Main ./REPL[6]:1
 [2] top-level scope
   @ REPL[7]:1

julia> maybe = true
WARNING: redefinition of constant maybe. This may fail, cause incorrect answers, or produce other errors.
true

julia> g()
ERROR: AssertionError: Hello world
Stacktrace:
 [1] g()
   @ Main ./REPL[6]:1
 [2] top-level scope
   @ REPL[9]:1

```

I’ll also that if you run Julia with `-O0` (optimization level 0) that you get a more complicated `f()`:

```julia
julia> f() = @assert true
f (generic function with 1 method)

julia> @code_llvm f()
; @ REPL[9]:1 within `f`
define void @julia_f_115() #0 {
top:
  %thread_ptr = call i8* asm "movq %fs:0, $0", "=r"()
  %ppgcstack_i8 = getelementptr i8, i8* %thread_ptr, i64 -8
  %ppgcstack = bitcast i8* %ppgcstack_i8 to {} ****
  %pgcstack = load {} ***, {}**** %ppgcstack, align 8
  %0 = bitcast {} ***%pgcstack to {}**
  %current_task = getelementptr inbounds {}*, {}** %0, i64 -13
  %1 = bitcast {}** %current_task to i64*
  %world_age = getelementptr inbounds i64, i64* %1, i64 14
  ret void
}

```

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [April 30, 2023, 12:34am UTC](https://discourse.julialang.org/t/how-to-omit-type-assertion-from-compiled-output/98090/9 "2023-04-30T00:34:16Z")

</div>

> [@mkitti](#):
>
> This suggests that there may be some optimization level that may omit an assertion.

It might, but currently isn’t. There is an [open PR](https://github.com/JuliaLang/julia/pull/37874) to enable removal of `@assert` in non-debug mode.
