World age issue due to code generation inside an inner constructor in Julia v0.6

I get a world age error in Julia v0.6 related to the fact that I code-generate two functions from inside an inner constructor here. The code-generated functions can not be called anymore in Julia v0.6, although this used to work in Julia v0.5. Is there an easy fix for this problem?

Couldn’t you swap the eval + codegen for a macro @codegen that simply inserts the expression for the function you are defining? You might have to refactor some stuff but calling eval like that is a bit unusual.

1 Like

Thanks Kristoffer, I will try, although I am afraid that the refactoring may not be straightforward. I will try what you suggested.

So, to have a working example, I first define below an add() function, the way I do it now:

function evalcodegen()
  body = []

  push!(body, :(return _x+_y))

  @gensym add

  quote
    function $add(_x, _y)
      $(body...)
    end
  end
end

f = eval(evalcodegen())

f(1, 2)

Here is the corresponding macro version:

macro macrocodegen(x, y)
 :($x+$y)
end

@macrocodegen(1, 2)

All this makes sense. But what happens when I want to assign a function to a type’s field, as in the snippet below? I think a macro wouldn’t work in the “?” placeholder I created.

type MyType
  f::Function

  function T()
    instance = new()
    instance.f = ?
  end
end

Something like this perhaps (note that I am creating an anonymous function):

macro evalcodegen()
  body = []
  push!(body, :(return _x+_y))
  return quote
    function (_x, _y)
      $(body...)
    end
  end
end

type MyType
  f::Function

  function MyType()
    instance = new()
    instance.f = @evalcodegen()
    return instance
  end
end

Yes, this snippet works. There is still another catch in my code that doesn’t allow me to use macros yet. Is it possible to pass an argument by value rather than by name in a macro?

julia> macro mymacro(x::Int64)
         :(print($x))
       end
@mymacro (macro with 1 method)

julia> @mymacro(2)
2
julia> x = 2
2

julia> @mymacro(x)
ERROR: MethodError: no method matching @mymacro(::Symbol)
Closest candidates are:
  @mymacro(::Int64) at REPL[1]:2

@mymacro(2) will work, but if I want to pass x as input argument, as in @mymacro(x), it won’t work.

That sounds like a function.

Perhaps you can show a minimal example again of what you want to do.

I just found another solution Kristoffer, by deferring a call to a code-generated function till later on (thankfully this delay in the function call seems to be ok conceptually). Thanks for your support and time.

Kristoffer, it turned out that the package is still broken. I will try to explain where the issue appears. The following works:

macro evalcodegen(z::Real)
  body = []
  push!(body, :(return _x+_y+$z))
  return quote
    function (_x, _y)
      $(body...)
    end
  end
end

type MyType
  f::Function

  function MyType()
    instance = new()
    instance.f = @evalcodegen(3)
    return instance
  end
end

t = MyType()
println(t.f(1, 2))

However, if I try to pass an input argument to the inner constructor MyType there is a problem (due to the macro):

macro evalcodegen(z::Real)
  body = []
  push!(body, :(return _x+_y+$z))
  return quote
    function (_x, _y)
      $(body...)
    end
  end
end

type MyType
  f::Function

  function MyType(x)
    instance = new()
    instance.f = @evalcodegen(x)
    return instance
  end
end

t = MyType(2)
println(t.f(1, 2))

Is there a work around this situation?

This works fine:

macro evalcodegen(z)
         body = []
         push!(body, :(return _x+_y+$(esc(z))))
         return quote
           function (_x, _y)
             $(body...)
           end
         end
       end

Is that what you’re looking for?

Thanks Keno.

Keno, while working on migrating from eval() function calls to macro calls to avoid more world age problems, I encountered yet another difficulty. I am attempting to clarify the new issue below, by means of a non-sensical trivial example. The following works:

macro codegen(y)
  quote
    function (x::$(typeof(y)))
      x+1
    end
  end
end

f = @codegen(2.)
f(3.)

However, if I try to call the macro from inside a function (function g() below), the following fails:

g(y) = @codegen(y)

f = g(2.)
f(3.)

Is there a way to solve this issue by possibly modifying the macro somehow?

Macros can’t do anything that regular syntax can’t, so this doesn’t work:

g(y) = function (x::typeof(y))
end

but this does, so maybe you can make that work

g(y::T) where {T} = function (x::T)
end

I see Keno, thanks for clarifying.