Help reading @code_warntype output

I’m attempting to learn a bit about how to read the output of @code_warntype

If I have a function like

function myGlob(pattern::Regex, to_search::Vector{String})::Vector{String}
    """
    Something similar to glob
    """
    m = [match(pattern, str) for str in to_search]
    return to_search[m .!= nothing]
end

Running @code_warntype on this, I get

@code_warntype myGlob(r"a", readdir())
Body::Array{String,1}
2 1 ─ %1  = %new(getfield(Main, Symbol("##9#10")){Regex}, glob_regex)::getfield(Main, Symbol("##9#10")){Regex}                                                  │     
  │   %2  = %new(Base.Generator{Array{String,1},getfield(Main, Symbol("##9#10")){Regex}}, %1, vec_of_strings)::Base.Generator{Array{String,1},getfield(Main, Symbol("##9#10")){Regex}}
  │   %3  = invoke Base.collect(%2::Base.Generator{Array{String,1},getfield(Main, Symbol("##9#10")){Regex}})::AbstractArray                                     │     
3 │   %4  = Base.Broadcast.materialize::Core.Compiler.Const(Base.Broadcast.materialize, false)                                                                  │     
  │   %5  = Main.:!=::Core.Compiler.Const(!=, false)                                                                                                            │     
  │   %6  = %new(Base.RefValue{Nothing}, nothing)::Base.RefValue{Nothing}                                                                                       ││╻╷╷╷  broadcastable
  │   %7  = (Base.Broadcast.combine_styles)(%3, %6)::Any                                                                                                        │╻     broadcasted
  │   %8  = (Base.Broadcast.broadcasted)(%7, %5, %3, %6)::Any                                                                                                   ││    
  │   %9  = (%4)(%8)::Any                                                                                                                                       │     
  │   %10 = (Base.getindex)(vec_of_strings, %9)::Any                                                                                                            │     
  │   %11 = (Base.convert)(Array{String,1}, %10)::Any                                                                                                           │     
  │         (Core.typeassert)(%11, Array{String,1})                                                                                                             │     
  │   %13 = π (%11, Array{String,1})                                                                                                                            │     
  └──       return %13 

I gather that the blue ::Array{String,1} at the top is probably good, but there are a couple red ::Anys in there, as well as a red ::AbstractArray

What exactly do they mean, and is there way to make them better? Should I try to make them better?

2 Likes

Unrelated to your question, you’ll want to put the docstring above the function signature to have it attached to the function, rather than in the function body (different from Python).

The red ::Any and ::AbstractArray signify that inference could not determine a concrete type for these variables, meaning that calling functions with these variables as inputs will involve dynamic dispatch: which method is called will be determined at runtime rather than at compile time, which has a performance cost.

In this case, the abstract inferred types are caused by the fact that match may return either a RegexMatch or nothing, so the element type of [match(pattern, str) for str in to_search] can’t be narrowed down to a concrete type at compile time.

A more efficient implementation could be:

"""
Something similar to glob
"""
function myGlob(pattern::Regex, to_search::AbstractVector{<:AbstractString})
    filter(str -> occursin(pattern, str), to_search)
end
7 Likes