# Constraints for \`@generated\` function

**URL:** <https://discourse.julialang.org/t/constraints-for-generated-function/27967>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 25, 2019, 6:34pm UTC](https://discourse.julialang.org/t/constraints-for-generated-function/27967 "2019-08-25T18:34:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [August 25, 2019, 6:34pm UTC](https://discourse.julialang.org/t/constraints-for-generated-function/27967/1 "2019-08-25T18:34:19Z")

</div>

It’s really not clear to me what is and isn’t allowed in a generated function. I get this error:

> ERROR: generated function body is not pure. this likely means it contains a closure or comprehension.

Ok, but where’s the problem? Is there any way of narrowing it down? Especially confusing is trying to pin down exactly what closures are unallowable. For example, this code works with no problems:

```julia
@generated function foo(x)
    g(y) = :($(one(x)) + $(one(y)))
    g(x)
end

```

So maybe the limitation is not really with closures, but state that’s stored outside the generated function. Is that right?

My generated code had called functions that call `gensym` or `rand`, and I’ve been moving things around with no luck yet. It feels like I’m stumbling around in the dark here, are there any guidelines for debugging generated functions I should be following?

---

<div class="post-metadata">

**Author:** ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)\
**Post date:** [August 26, 2019, 3:47am UTC](https://discourse.julialang.org/t/constraints-for-generated-function/27967/2 "2019-08-26T03:47:07Z")

</div>

I’ve made progress on this thanks to helpful guidance from @thautwarm. Here’s my current understanding of the constraints, in case it might be helpful to others:

Like macros, a generated function requires building an AST. Most discussions of “code in generated functions” aren’t very clear about this, but there are really two kinds of code involved, with different constraints:

- There’s the code you use the build the AST. The constraints on this are relatively loose. The big thing is, there are no guarantees regarding when it will execute, so you should avoid referencing global state. Also as I understand it, `eval` is disallowed here.  
Also, any reference in this code to the value passed to the function will be interpreted not as the value, but as its type (good details on this part in the docs).

- Then there’s the code that actually ends up in the AST. Here the value passed in refers to the actual value, but you need to interpolate with `$` to express it. Also, this portion is very constrained in that it does not allow closures (it’s fine to call a closure from a generated function, but _not within the AST_. A closure is a function that refers to values outside its scope.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [August 26, 2019, 6:26am UTC](https://discourse.julialang.org/t/constraints-for-generated-function/27967/3 "2019-08-26T06:26:01Z")

</div>

You’ve got the gist of it. To expand a little:

- The _generator_ code (used to build the AST from the argument types) cannot call functions _or methods_ which are defined after the generated function is defined. So you can’t generally call things like trait functions within your generator if they may be overloaded for user defined types. This may eventually be fixed in a future julia version with some sufficiently clever tracking of function dependencies (“backedges”), we will see.
- The _generated_ code (which is invoked on the argument values) can call any function, but it may not define new types. This means it can’t use closures because closures are lowered to new types internally. I believe this may also eventually be fixed, but for now we need to put up with it.
