Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do get values of out a `do` block in Julia?

Tags:

scope

julia

I have an HDF5 file I'd like to read 2 arrays from. How can I get them using the do block notation?

using HDF5

function myfunc()
    h5open("path", "r") do f
        a = read(f, "a")
        b = read(f, "b")
    end

    # ... do some more processing of a, b
    return a, b
end

If I run that, it will error after the do block with a not defined. How do I get the values so I can process them after, without wrapping the full computation in the do block?

like image 644
DVNold Avatar asked Oct 16 '25 02:10

DVNold


2 Answers

A do block is just syntax for creating an anonymous function that is passed as the first argument (to h5open in this case`). Just like regular functions, you need to return any values from the anonymous function that you want to use on the "outside":

# Function to mimic Base.open, HDF5.h5open etc
function open(f)
    return f()
end

function g()
    a, b = open() do
        c = "hello"
        d = "world"
        return c, d # returns from the "do"-anonymous function
    end
    return a, b
end
like image 152
fredrikekre Avatar answered Oct 18 '25 16:10

fredrikekre


You can define local variables in the outer function like this:

julia> function f()
           local a, b
           map(10) do x
               a = x + 1
               b = x + 2
           end
           return a, b
       end
f (generic function with 1 method)

julia> f()
(11, 12)

The downside of this approach is that compiler will not be able to make it type stable in all cases and also might be boxing a and b (both things happen in my example). What @fredrikekre proposes is a preferred approach AFAICT. See:

julia> @code_warntype f()
Variables
  #self#::Core.Compiler.Const(f, false)
  b@_2::Core.Box
  a@_3::Core.Box
  #1::var"#1#2"
  a@_5::Union{}
  b@_6::Union{}

Body::Tuple{Any,Any}
1 ─       (b@_2 = Core.Box())
│         (a@_3 = Core.Box())
│         (#1 = %new(Main.:(var"#1#2"), b@_2, a@_3))
│   %4  = #1::var"#1#2"
│         Main.map(%4, 10)
│   %6  = Core.isdefined(a@_3, :contents)::Bool
└──       goto #3 if not %6
2 ─       goto #4
3 ─       Core.NewvarNode(:(a@_5))
└──       a@_5
4 ┄ %11 = Core.getfield(a@_3, :contents)::Any
│   %12 = Core.isdefined(b@_2, :contents)::Bool
└──       goto #6 if not %12
5 ─       goto #7
6 ─       Core.NewvarNode(:(b@_6))
└──       b@_6
7 ┄ %17 = Core.getfield(b@_2, :contents)::Any
│   %18 = Core.tuple(%11, %17)::Tuple{Any,Any}
└──       return %18
like image 38
Bogumił Kamiński Avatar answered Oct 18 '25 14:10

Bogumił Kamiński



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!