# Using metaprogramming to define a bunch of methods at once

**URL:** <https://discourse.julialang.org/t/using-metaprogramming-to-define-a-bunch-of-methods-at-once/23663>\
**Category:** General Usage\
**Created:** [April 29, 2019, 6:19pm UTC](https://discourse.julialang.org/t/using-metaprogramming-to-define-a-bunch-of-methods-at-once/23663 "2019-04-29T18:19:22Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![doomphoenix-qxz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doomphoenix-qxz/32/7009_2.png) [@doomphoenix-qxz](https://discourse.julialang.org/u/doomphoenix-qxz)\
**Post date:** [April 29, 2019, 6:19pm UTC](https://discourse.julialang.org/t/using-metaprogramming-to-define-a-bunch-of-methods-at-once/23663/1 "2019-04-29T18:19:22Z")

</div>

I’m trying to replicate the following trick that I found in SpecialFunctions.jl/src/bessel.jl:

```
## Bessel functions

```

```julia
# besselj0, besselj1, bessely0, bessely1
for jy in ("j","y"), nu in (0,1)
    jynu = Expr(:quote, Symbol(jy,nu))
    jynuf = Expr(:quote, Symbol(jy,nu,"f"))
    bjynu = Symbol("bessel",jy,nu)
    if jy == "y"
        @eval begin
            $bjynu(x::Float64) = nan_dom_err(ccall(($jynu,libm), Float64, (Float64,), x), x)
            $bjynu(x::Float32) = nan_dom_err(ccall(($jynuf,libm), Float32, (Float32,), x), x)
            $bjynu(x::Float16) = Float16($bjynu(Float32(x)))
        end
    else
        @eval begin
            $bjynu(x::Float64) = ccall(($jynu,libm), Float64, (Float64,), x)
            $bjynu(x::Float32) = ccall(($jynuf,libm), Float32, (Float32,), x)
            $bjynu(x::Float16) = Float16($bjynu(Float32(x)))
        end
    end
    @eval begin
        $bjynu(x::Real) = $bjynu(float(x))
        $bjynu(x::Complex) = $(Symbol("bessel",jy))($nu,x)
    end
end

```

Here’s the code snippet that gives my MWE:

```julia
const Phases = @enum solid liquid vapor

struct CpData1{T}
    Tmin::T
    Tmax::T
    a::T
    b::T
    c::T
    d::T
    phase::Phases
end

function minimumtemp(dat::CpData1, T) end
function maximumtemp(dat::CpData1, T) end

for aphase in [:solid, :liquid, :vapor] 
    for acond in [:maximum, :minimum]
        @eval begin
            fname1 = Symbol(acond, "temp_", aphase) 
            fname2 = Symbol(acond, "temp")
            $fname1(dat::MultiCp, T) = $fname2(dat, dat.phaseranges[Phases::$aphase])
        end
    end
end

```

This gives the following errors:

`UndefVarError: CpData1 not defined` and `UndefVarError: fname1 not defined`.

I have a few questions about this. First, does the first error mean that I can’t use a struct defined in the same file because `@eval` executes before Julia has executed the struct definition? Second, I don’t understand the `fname` error at all because I think I’m using `fname1` EXACTLY the same way that `bjynu` is being used in SpecialFunctions.jl. What am I missing here?

Thanks!

---

<div class="post-metadata">

**Author:** ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)\
**Post date:** [April 29, 2019, 6:45pm UTC](https://discourse.julialang.org/t/using-metaprogramming-to-define-a-bunch-of-methods-at-once/23663/2 "2019-04-29T18:45:00Z")

</div>

Looks like `Phases` is not a julia `Type` so `CpData1{T}` is not a valid definition. Secondly, you interpolate `fname1` and `fname2` even though you do not have these defined yet. Third, you cannot define a name to be both a _value_ and a _function_ simultaneously, which you are attempting with the names of `fname1` and `fname2`. Instead, the symbol definitions must happen outside of the `@eval` statement so that they can be interpolated.

```nohighlight
const Phases = @enum solid liquid vapor

struct CpData1{T}
    Tmin::T
    Tmax::T
    a::T
    b::T
    c::T
    d::T
    phase
end

function minimumtemp(dat::CpData1, T) end
function maximumtemp(dat::CpData1, T) end

for aphase in [:solid, :liquid, :vapor] 
    for acond in [:maximum, :minimum]
        fname1 = Symbol(acond, "temp_", aphase) 
        fname2 = Symbol(acond, "temp")
        @eval $fname1(dat::MultiCp, T) = $fname2(dat, dat.phaseranges[Phases::$aphase])
    end
end

```

Also, `MultiCp` is not defined.

---

<div class="post-metadata">

**Author:** ![doomphoenix-qxz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doomphoenix-qxz/32/7009_2.png) [@doomphoenix-qxz](https://discourse.julialang.org/u/doomphoenix-qxz)\
**Post date:** [April 29, 2019, 7:36pm UTC](https://discourse.julialang.org/t/using-metaprogramming-to-define-a-bunch-of-methods-at-once/23663/3 "2019-04-29T19:36:24Z")

</div>

I think this:

> Instead, the symbol definitions must happen outside of the `@eval` statement so that they can be interpolated.

was the real key for me, though I guess I was confused about Enums as well (I actually thought every enum _was_ its own type for some reason). After making the edits you suggested, it seems to work great! Thanks.

MultiCp exists in the original file; I just forgot to add it when extracting my MWE code.
