# Scope of expressions returned from @generated functions

**URL:** <https://discourse.julialang.org/t/scope-of-expressions-returned-from-generated-functions/51241>\
**Category:** General Usage\
**Tags:** metaprogramming\
**Created:** [December 4, 2020, 9:42am UTC](https://discourse.julialang.org/t/scope-of-expressions-returned-from-generated-functions/51241 "2020-12-04T09:42:16Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![dafred](https://avatars.discourse-cdn.com/v4/letter/d/7ab992/32.png) [@dafred](https://discourse.julialang.org/u/dafred)\
**Post date:** [December 4, 2020, 9:42am UTC](https://discourse.julialang.org/t/scope-of-expressions-returned-from-generated-functions/51241/1 "2020-12-04T09:42:17Z")

</div>

So I want to create models that have a similar calculation graph but differ in small aspects.  
Each model is represented as a struct with matching dispatches for function calc.  
To demonstrate what I have so far, I created the following script:

```julia
#file: demonstration.jl
abstract type AbstractT end

""" concreteT1 and concreteT2 have different parameter sets """
struct concreteT1 <: AbstractT
    a
    b
    c
end

struct concreteT2 <: AbstractT
    a
    b
    c
    p
end

""" the function body into which expressions have to be inserted via 
expression ex_de """
macro calc_body(ex_de)
    return esc(quote

    a = ob.a
    b = ob.b
    c = ob.c

    d,e = $ex_de

    d += 1
    e += 2

    return a + b / (d*e)
    end)
end

""" calc shall be able to be called with both concreteT1 and concreteT2"""
function calc(ob::AbstractT)
    @calc_body(inserted_expression(ob))
end

""" expressions which can be inserted into calc_body """
macro de1()
    return esc(:((0, 0)))
end

macro de2()
    return esc(:((a/b, a*b*p)))
end

""" these functions decide, with type information about ob, which expression 
will be inserted into calc_body during a call to calc(AbstractT)"""
@generated function inserted_expression(ob::concreteT1)
    return @de1
end

@generated function inserted_expression(ob::concreteT2)
    return @de2
end

function main()

    """ works as expected """
    ob = concreteT1(1, 2, 3) 
    
    """ UndefVarError will be thrown when trying to access a 
    (that should be known inside calc_body)"""
    #ob = concreteT2(1, 2, 3, 4) 

    result = calc(ob)
    println(result)
end

main()

```

So far, only calc(concreteT1) works, but not calc(concreteT2). An UndefVarError is thrown when trying to access variable “a” that, from my point of view, should be known within calc\_body, where the returned expression from macro de2 is inserted.

I tried to esc() the returned expression from inserted\_expression(concreteT2) but I it wouldn’t help either…

**Why am I not just using functions instead of trying to generate functions?**  
I would like to be able to access every temporary variable known in calc\_body and not think about what exactly goes into the code which calculates “d” and “e”.

**Why am I not just moving the content from de2 to inserted\_expression(concreteT2)?**  
In reality, calc\_body can be modified at multiple points, not just with “ex\_de”. If I then add concreteT3 that shares “ex\_de” with concreteT1, but has another “ex\_xy” (just an example), i want to reuse the expression that the existing macro de1 already returns.

I hope that I could make clear what my question is: **Why do I get the UndefVarError?** Can i change my code so that “a” will be known in the expression that de2 returns?

I am also open to criticism regarding my architecture itself.
