Julia: Generated functions as closures

Created on 30 Sep 2016  路  9Comments  路  Source: JuliaLang/julia

f(x) = @generated g() = x
julia> f(1)()
ERROR: type DataType has no field x
 in g(...) at ./REPL[1]:1

As performed in 0.5.0 and 0.6.0-dev.826.
:?

julia> @code_lowered f(1)()
CodeInfo(:(begin 
        nothing
        return (Core.getfield)(#self#,:x)
    end))
bug lowering

Most helpful comment

Yes, I think it would be reasonable for generated functions to still capture variables by value. Arguably @generated only causes the generator's arguments to be bound to types, and nothing else.

To give a reason, functions are not specialized on the types of captured variables, _unless_ those are reflected in the type of the function itself, which is already an argument. So generated functions do not need their captured variables to become types.

All 9 comments

This issue seems to apply to inner generated functions generally:

julia> function f(x)
       @generated g() = x
       g
       end;

julia> f(1)()
ERROR: type DataType has no field x
 in g(...) at ./REPL[1]:2

This may be similar to #15602 and #18674, in that it is no longer permitted but doesn't have an appropriate error message.

Oh, that's nice to know. I just tried something like this and it worked:

function f(x)
  @generated function()
    x
  end
end
julia> f(1)()
1

So I assumed it was a macro thing. I will update the issue, then.

I'm not sure how easily this can be fixed, but the correct answer should have been Int in all of the above examples (since the function generator capture types, not values).

@vtjnash yeah, I later realized that the above gave a 1 because @generated function() ... end doesn't create a generated function at all, it just returns the function itself. That's a separate issue I guess.

f = @generated function() end
g = @generated function h() end
julia> methods(f).ms[1].isstaged
false

julia> methods(g).ms[1].isstaged
true

@vtjnash hey wait, you sure? The "@generated function() end doesn't work" issue is true, but the "generated closure captures types" isn't consistent with other outside variables:

x = 1
@generated f() = x
julia> f()
1

julia> methods(f).ms[1].isstaged
true

Yes, I think it would be reasonable for generated functions to still capture variables by value. Arguably @generated only causes the generator's arguments to be bound to types, and nothing else.

To give a reason, functions are not specialized on the types of captured variables, _unless_ those are reflected in the type of the function itself, which is already an argument. So generated functions do not need their captured variables to become types.

True, this is perhaps one way we could allow inner generated functions to capture variables, by requiring that the generator also reference that variable? The implementation of such sounds quite annoying.

However, the following would need to hold in order for the cached code to have only depended on the type #g#f{typeof(x)}, which is why in the above example, the correct answer would be Int:

function g(x)
   @generated f()
       return :(x :: $x)
   end
   return f
end

In your code example,

x = 1
@generated f() = x

you are missing a const declaration before the x for this to be a valid usage of generated functions. This is not capturing x, but creating a new const reference to it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sbromberger picture sbromberger  路  3Comments

Keno picture Keno  路  3Comments

felixrehren picture felixrehren  路  3Comments

omus picture omus  路  3Comments

iamed2 picture iamed2  路  3Comments