# Type instability for singleton tuple argument

**URL:** <https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147>\
**Category:** Performance\
**Tags:** inference, type\
**Created:** [September 6, 2020, 3:15pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147 "2020-09-06T15:15:35Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jlchan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlchan/32/10958_2.png) [@jlchan](https://discourse.julialang.org/u/jlchan)\
**Post date:** [September 6, 2020, 3:15pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/1 "2020-09-06T15:15:35Z")

</div>

why do I get type instability for the function `(x->x.^2).((1,))`? if my input argument is a singleton tuple, then `@code_warntype (x->x.^2).((1,))` gives

```julia
│ %4 = Base.materialize(%3)::Tuple{Any}
└── return %4

```

If the argument is not a singleton tuple, there doesn’t seem to be any type instability.

---

<div class="post-metadata">

**Author:** ![jlchan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlchan/32/10958_2.png) [@jlchan](https://discourse.julialang.org/u/jlchan)\
**Post date:** [September 6, 2020, 3:21pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/2 "2020-09-06T15:21:46Z")

</div>

I also noticed that after fiddling with things in the REPL for a while, I no longer get the type warning. However, I see the type warning again after restarting the REPL.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [September 6, 2020, 3:39pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/3 "2020-09-06T15:39:07Z")

</div>

> [@jlchan](#):
>
> `(x->x.^2).((1,))`

Not seeing that on Julia 1.5:

```julia
julia> @code_warntype (x->x.^2).((1,))
Variables
  #self#::Core.Compiler.Const(var"##dotfunction#253#8"(), false)
  x1::Tuple{Int64}
  #7::var"#7#9"

Body::Tuple{Int64}
1 ─ (#7 = %new(Main.:(var"#7#9")))
│ %2 = #7::Core.Compiler.Const(var"#7#9"(), false)
│ %3 = Base.broadcasted(%2, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,var"#7#9",Tuple{Tuple{Int64}}}
│ %4 = Base.materialize(%3)::Tuple{Int64}
└── return %4

```

---

<div class="post-metadata">

**Author:** ![jlchan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlchan/32/10958_2.png) [@jlchan](https://discourse.julialang.org/u/jlchan)\
**Post date:** [September 6, 2020, 3:47pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/4 "2020-09-06T15:47:05Z")

</div>

Odd. I’m running it on v1.5 too, and I get

```julia
@code_warntype (x->x.^2).((1,))
Variables
  #self#::Core.Compiler.Const(var"##dotfunction#253#16"(), false)
  x1::Tuple{Int64}
  #15::var"#15#17"

Body::Tuple{Any}
1 ─ (#15 = %new(Main.:(var"#15#17")))
│ %2 = #15::Core.Compiler.Const(var"#15#17"(), false)
│ %3 = Base.broadcasted(%2, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,var"#15#17",Tuple{Tuple{Int64}}}
│ %4 = Base.materialize(%3)::Tuple{Any}
└── return %4

```

I had to restart the REPL to see it. Does the warning show up if you do that?

---

<div class="post-metadata">

**Author:** ![jlchan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlchan/32/10958_2.png) [@jlchan](https://discourse.julialang.org/u/jlchan)\
**Post date:** [September 6, 2020, 4:04pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/5 "2020-09-06T16:04:15Z")

</div>

I got an answer on slack from @simeonschaub.

> The problem here seems to be that inlining gives up for x → x.^2, probably because it has to go through the whole broadcast machinery twice. This fixes it: `@code_warntype (x->(Base.@_inline_meta; x.^2)).((1,)).`

> If you don’t need all the broadcasting semantics, you’re usually better off just using `map` instead, e.g. `map(x->x.^2, (1,))` also infers just fine.

The latter `map` implementation is exactly what I was looking for.

I think I was under the wrong impression that broadcasting and map were somewhat equivalent.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [September 6, 2020, 4:09pm UTC](https://discourse.julialang.org/t/type-instability-for-singleton-tuple-argument/46147/6 "2020-09-06T16:09:47Z")

</div>

I think the problem you are running into here is that the machinery to make broadcasting work puts quite a bit of strain on the compiler and because you are trying to broadcast twice here, it seems to fail to inline `x -> x.^2`. You can encourage inlining manually like this:

```julia
julia> @code_warntype (@inline x -> x.^2).((1,))
Variables
  #self#::Core.Compiler.Const(var"##dotfunction#275#23"(), false)
  x1::Tuple{Int64}
  #22::var"#22#24"

Body::Tuple{Int64}
1 ─ (#22 = %new(Main.:(var"#22#24")))
│ %2 = #22::Core.Compiler.Const(var"#22#24"(), false)
│ %3 = Base.broadcasted(%2, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,var"#22#24",Tuple{Tuple{Int64}}}
│ %4 = Base.materialize(%3)::Tuple{Int64}
└── return %4

```

(note that on Julia versions older than 1.5, you need to write that as `(x -> (@_inline_meta; x.^2)).((1,))`)

A more general workaround for code like this is to rely less on broadcasting and prefer functions like `map`, which make inference’s job a lot easier. For example, this also infers just fine:

```julia
julia> @code_warntype map(x->x.^2, (1,))
Variables
  #self#::Core.Compiler.Const(map, false)
  f::Core.Compiler.Const(var"#15#16"(), false)
  t::Tuple{Int64}

Body::Tuple{Int64}
1 ─ %1 = Base.getindex(t, 1)::Int64
│ %2 = (f)(%1)::Int64
│ %3 = Core.tuple(%2)::Tuple{Int64}
└── return %3

```

`map` still does the same thing here, but its implementation is a lot less complicated than `broadcast`.
