@eval and module scope

metaprogramming

#1

(migrated from Slack)
Consider this code

function define_ops(x)
       for sym in (:pos, :pes)
               @eval $(sym)(y) = y + $x
       end
end

define_ops(2)
pos(3) #5

Works perfectly

But if I try to do it in a module (I believe eval works in module scope?), it doesn’t:

module FooMod
function define_ops(x)
       for sym in (:pos, :pes)
               @eval $(sym)(y) = y + $x
       end
end
export define_ops
export pos, pes
end

using FooMod
define_ops(2)
pos(3) # 'pos not defined' error

clearly something about scoping I don’t understand. What idiom would I use to make the below version work?


#2

I think you might need to eval in current_module():

eval(current_module(), ...)

(which might later be superseded by @__MODULE__)

help?> current_module
search: current_module

  current_module() -> Module

  Get the dynamically current Module, which is the Module code is currently being read from. In general, this is not the same as the module containing the call to this function.

#3

Seems to work for me

julia> module Foo
           function define_ops(x)
              for sym in (:pos, :pes)
                      @eval $(sym)(y) = y + $x
              end
           end
           export define_ops
           export pos
       end
Foo

julia> using Foo

julia> define_ops(3)

julia> pos(4)
7

julia> versioninfo()
Julia Version 0.6.1-pre.1
Commit 4b967d4a9d (2017-08-21 21:11 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin15.6.0)
  CPU: Intel(R) Core(TM) M-5Y51 CPU @ 1.10GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, broadwell)

#4

No don’t eval in current_module(). It is also NOT equivalent to @__MODULE__

Works fine on master

julia> module FooMod
       function define_ops(x)
              for sym in (:pos, :pes)
                      @eval $(sym)(y) = y + $x
              end
       end
       export define_ops
       export pos, pes
       end
Main.FooMod

julia> using .FooMod

julia> define_ops(2)

julia> pos(1)
3

julia> pos(2)
4

julia> pes(2)
4

#5

Wut? I’ll download a nightly and see if it’s a setup/version thing.


#6

I’ve no idea what went wrong, but the exact pasted code above worked after restarting my session.