Search code examples
juliatype-stability

Type-stable do-blocks in julia


I want to read data from a file with a do-block. Using a do-block it is quite important because I need to be sure that the file gets properly closed even if an error occurs during the reading of the file. The data in the file should be converted to the a type provided as argument. My real use case is to use NetCDF files, but I can reproduce the type stability issue with plain text file.

Assume, there is a file file.txt with the content 123, which can be created with:

 write("file.txt","123")

When I load the file without a do-block as follows, the result is type stable:

function loadfile1(T)
    f = open("file.txt")
    data = parse(T,readline(f))
    close(f)
    return data
end

@code_warntype infers correctly that I get Float32 as a result:

@code_warntype loadfile1(Float32)
Body::Float32
[...]

However, the following variant:

function loadfile2(T)
    f = open("file.txt") do f
        return parse(T,readline(f))
    end
end

produces a type-unstable code:

 @code_warntype loadfile2(Float32)
Body::Any
9 1 ─ %1 = %new(getfield(Main, Symbol("##842#843")){DataType}, T)::getfield(Main, Symbol("##842#843")){DataType}                                                                                  │ 
  │   %2 = Main.open::Core.Compiler.Const(open, false)                                                                                                                                            │ 
  │   %3 = invoke Base.:(#open#294)($(QuoteNode(Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}()))::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, %2::Function, %1::getfield(Main, Symbol("##842#843")){DataType}, "file.txt"::String)::Any
  └──      return %3            

How could I modify the function loadfile2 (with a do-block) and still get a type-stable result?


Solution

  • It works to move T to a type specification in the signature:

    function loadfile2(::Type{T}) where T
        f = open("file.txt") do f
            return parse(T,readline(f))
        end
    end
    

    This way T is known at compile time.