Skip to content

replace unable to determine type with broadcast, but can with a for-loop #44112

Open
@numbermaniac

Description

@numbermaniac

I had a 2D array of integers and used replace to replace some of them using a list of pairs.

function replace_listcomp(r :: Vector{Vector{Int}}, p :: Vector{Pair{Int, Int}})
    result = [replace(rr, p...) for rr in r]
    return result
end

With this list comprehension, Julia correctly determines the output type:

julia> @code_warntype replace_listcomp([[1,2,3]], [1 => 10])
# output cropped to relevant part
Locals
  #1::var"#1#2"{Vector{Pair{Int64, Int64}}}
  result::Vector{Vector{Int64}}
Body::Vector{Vector{Int64}}

I then changed the function to use broadcast syntax instead, but surprisingly, it was no longer able to determine the output type.

function replace_broadcast(r :: Vector{Vector{Int}}, p :: Vector{Pair{Int, Int}})
    result = replace.(r, p...)
    return result
end
julia> @code_warntype replace_broadcast([[1,2,3]], [1 => 10])
# [...]
Arguments
  #self#::Core.Const(replace_broadcast)
  r::Vector{Vector{Int64}}
  p::Vector{Pair{Int64, Int64}}
Locals
  result::Any
Body::Any
1%1 = Core.tuple(Main.replace, r)::Tuple{typeof(replace), Vector{Vector{Int64}}}%2 = Core._apply_iterate(Base.iterate, Base.broadcasted, %1, p)::Any
│        (result = Base.materialize(%2))
└──      return result

It now says the output type is just Any. I expected that it would say Vector{Vector{Int64}} instead, just like the previous example.


Interestingly though, it does figure out the output type if I change the p argument from a vector to a tuple.

function replace_broadcast_tuple(r :: Vector{Vector{Int}}, p :: Tuple{Vararg{Pair{Int, Int}}})
    result = replace.(r, p...)
    return result
end
julia> @code_warntype replace_broadcast_tuple([[1,2,3]], (1 => 10, 2 => 15))
# [...]
Arguments
  #self#::Core.Const(replace_broadcast_tuple)
  r::Vector{Vector{Int64}}
  p::Tuple{Pair{Int64, Int64}, Pair{Int64, Int64}}
Locals
  result::Vector{Vector{Int64}}
Body::Vector{Vector{Int64}}
1%1 = Core.tuple(Main.replace, r)::Tuple{typeof(replace), Vector{Vector{Int64}}}%2 = Core._apply_iterate(Base.iterate, Base.broadcasted, %1, p)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(replace), Tuple{Vector{Vector{Int64}}, Base.RefValue{Pair{Int64, Int64}}, Base.RefValue{Pair{Int64, Int64}}}}
│        (result = Base.materialize(%2))
└──      return result

While I've already found a workaround that doesn't use replace at all, I figured I'd post this anyway since it surprised me when I encountered it.

julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions