# Create dynamic functions with Macro

**URL:** <https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824>\
**Category:** General Usage\
**Tags:** macros, metaprogramming\
**Created:** [September 24, 2024, 5:48pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824 "2024-09-24T17:48:42Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 24, 2024, 5:48pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/1 "2024-09-24T17:48:42Z")

</div>

Hi,

I’m trying create “dynamic” functions with macro, but it isn’t working. Let-me explain:

I’ve this function:

```julia
function f(::Type{T}, message) where T
    println("Type: ", T)
    println("Message: ", message)
end

```

When I call it `f(Int, "Hi")`, the output is:

```console
Type: Int64
Message: Hi

```

Nice! Now I have the dictionary:

```julia
map = Dict( Int => "Hello", Float64 => "Hey!", UInt => "Bye" );

```

And I want dynamic create a function `f2(Int)`, `f2(Float64)` and `f2(UInt)` based at `map` values.

Something like this that works fine, but at this case this `f2` will only generate the cases that I manualy added at this code:

```julia
macro create_desired(map)
    return esc(Expr(:block, [
                :( f2(::Type{Int}) = f(Int, map[Int]) ),
                :( f2(::Type{Float64}) = f(Float64, map[Float64]) ),
                :( f2(::Type{UInt}) = f(UInt, map[UInt]) ),
                ]...))
end

```

After `@create_desired(map)`, when I call `f2(Int)`, `f2(Float64)` and `f2(UInt)`, the output is respectly:

```console
Type: Int64
Message: Hello

```

```console
Type: Float64
Message: Hey!

```

```console
Type: UInt64
Message: Bye

```

If you read at this point, I think do you know what I want. I tried something like this, but it isn’t working:

```julia
macro create(map)
    return esc(Expr(:block, [
                :( function f2(::Type{T}) where T
                        return f(T, msg)
                   end
                    for (T, msg) in map )
                ]...))
end

```

I think it’s a problem with scope at this code. And tried this:

```julia
macro create2(map)
    exprs = []
    
    :(
        for (T, msg) in $map
            push!($exprs, function f2(::Type{T}) where T
                                return f(T, msg)
                          end )
        end
    )
                    
    
    return esc(Expr(:block, exprs...))
end

```

Someone, know how to solve this problem?

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [September 24, 2024, 6:21pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/2 "2024-09-24T18:21:28Z")

</div>

Here is a simple solution that seems to fit your requirements to me, but it looks pretty different than what you’ve tried so maybe I’m missing something:

```julia
mymap = Dict(Int => "Hello", Float64 => "Hey!", UInt => "Bye")

function f2 end

for (t, v) in mymap
  @eval f2(::Type{$t}) = println($v)
end

```

Is something like this what you are looking for?

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [September 24, 2024, 6:38pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/3 "2024-09-24T18:38:27Z")

</div>

This should work with no eval needed!

```julia
function make_f2(mymap)
    # turn it into a NamedTuple so lookup is a constant
    named_tuple_map = (; (Symbol(k) => v for (k,v) in pairs(mymap))...)
    # anon function that looks up the right value
    return function (::Type{T}) where T
        sym_t = Symbol(T)
        msg = named_tuple_map[sym_t]
        return f(T, msg)
    end
end

mymap = Dict(Int => "Hello", Float64 => "Hey!", UInt => "Bye")

const f2 = make_f2(mymap)
```

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 24, 2024, 7:26pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/4 "2024-09-24T19:26:01Z")

</div>

Hi @cgeoga ,

First, thanks for you answer. I suggested macro because a wanna define how to create the function at one module but create the function at other scope.

Let-me explain this structure:

```julia
module B	
	function create_f2(map)
		for (t, v) in map
		  @eval f2(::Type{$t}) = println($v)
		end
	end
	
	export create_f2
end

```

```julia
module A
	using Main.B
	
	map = Dict( Int => "Hello", Float64 => "Hey!", UInt => "Bye" )

	function f2 end
	
	create_f2(map)
	
	f2(Int)
	
	f2(Float64)
	
	export f2
end

```

I want define how to create `f2` at Module `B` but I want module A own `f2` function.

I tried your solution with this struct, but it isn’t working.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 24, 2024, 9:38pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/5 "2024-09-24T21:38:29Z")

</div>

What are you ultimately trying to do?

This seems like a [classic XY problem](https://en.wikipedia.org/wiki/XY_problem), where you are [reaching for metaprogramming](https://discourse.julialang.org/t/how-to-warn-new-users-away-from-metaprogramming/35022) when you should be using higher-order functions or similar.

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 25, 2024, 11:08am UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/6 "2024-09-25T11:08:23Z")

</div>

Hi @stevengj , I want create functions `f2()` on a module `B`, `C`, `D`…, but I want define how to create this function at another module `A`.

Theses modules `B`, `C`, `D`…, uses the same function with the same structure/sequence, but each module have your own implementations of `f()` function. For example, `B` can insert an user at DB, `C` can insert a bank at DB, etc.

@stevengj , the big problem it isn’t generate one function, the real problem is genereate functions for many entities at one call of macro. For example: module `B` has entities user, sale and payment. I know how to construct these insert functions calling one macro for each entity like:

```julia
@create_insert(User, "user")
@create_insert(Sale, "sale")
@create_insert(Payment, "payment")

```

The problem is:

```julia
@create_insert( Dict(User => "user", Sale => "sale", Payment => "payment" ))

```

I’m trying to do this at webservice REST context to receive requests from the user, but I think is the same problem. At first definition, I simplified the context, because I think the problem happens at multiple contexts and if I coulld define is:

Create a macro that dynamically create `k` functions by a dictionary/array given at parameter.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 11:36am UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/7 "2024-09-25T11:36:10Z")

</div>

> [@Ronneesley](#):
>
> Theses modules `B`, `C`, `D`…, uses the same function with the same structure/sequence, but each module have your own implementations of `f()` function. For example, `B` can insert an user at DB, `C` can insert a bank at DB, etc.

So write a higher-order function: define a single function `f2` in module `A`, but have it take the function `f` as a parameter. Then other modules can call `A.f2` and pass their own `f` functions.

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 25, 2024, 11:47am UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/8 "2024-09-25T11:47:02Z")

</div>

Yeh @stevengj I thought solution, and let me explain why at my case is not a good solution.

At my real context the problem is something like this:

```julia
@create_insert_process_request( Dict(User => "user", Sale => "sale", Payment => "payment" ))

```

And process request is something like:

```julia
function insert_process_request(r::Request, ::Type{User})
  check_permission_at_header(r, "user-identifier", "insert-action")
  data = get_post_data(r) #At this point data can be an User
  con = connect_with_db()
  process_request(con, data)
  close_db_conection!(con)
  return Response("Message of success")
end

```

Supose I’m writing module `B` with this function `insert_process_request()`,  
note that I have to create a similar function for `Sale` and `Payment`. Let me write for `Sale`

```julia
function insert_process_request(r::Request, ::Type{Sale})
  check_permission_at_header(r, "sale-identifier", "insert-action")
  data = get_post_data(r) #At this point data can be an User
  con = connect_with_db()
  process_request(con, data)
  close_db_conection!(con)
  return Response("Message of success")
end

```

Note this function is almost the same. If these functions happens only at module `B`, I could write something like this:

```julia
function insert_process_request(r::Request, ::Type{T}) where T <: Union{User, Sale, ...}
  check_permission_at_header(r, "PROBLEM-identifier", "insert-action")
  data = get_post_data(r) #At this point data can be an User
  con = connect_with_db()
  process_request(con, data)
  close_db_conection!(con)
  return Response("Message of success")
end

```

The problem begins at securty identifier, because it’s specific, and can be a very different value. For example the natural is think the entity `User` has identifier `user-identifier`, `Sale` has identifier `sale-identifier`, etc. But I think that is not health fix this, for example an entitty `UserStatus` can have a identifier at security system only `status-identifier`, and I don’t see problem with this differences.

I can create a macro to solve this calling:

```julia
@create_insert_process_request(User, "user-identifier")
@create_insert_process_request(Sale, "sale-identifier")
@create_insert_process_request(Payment, "user-identifier")

```

This code is very ugly, but works. Why I can’t solve this with one macro call?

About a high order function at module `A`, almost all function at this problem is need at parameter, something like this:

```julia
function insert_process_request_highorder(r::Request, identifier::String, action::String, 
get_post_data::Function, connect_with_db::Function, 
process_request::Function, close_db_conection!::Function) 
  check_permission_at_header(r, identifier, action)
  data = get_post_data(r) #At this point data can be an User
  con = connect_with_db()
  process_request(con, data)
  close_db_conection!(con)
  return Response("Message of success")
end

```

At module `B` I should define one by one function

```julia
insert_process_request(r::Request, ::Type{User}) =
       insert_process_request_highorder(r, "user-identifier", 
         get_post_data_user, connect_with_db_module_B, 
         process_user_request, close_db_connection_module_B!)

insert_process_request(r::Request, ::Type{Sale}) =
       insert_process_request_highorder(r, "sale-identifier", 
         get_post_data_sale, connect_with_db_module_B, 
         process_user_request, close_db_connection_module_B!)

```

And then I fall into the same problem 🥲.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 12:32pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/9 "2024-09-25T12:32:20Z")

</div>

> [@Ronneesley](#):
>
> Note this function is almost the same.

Right, so refactor out the common parts. For example:

```julia
function insert_process_request(r::Request, request_type::AbstractString)
  check_permission_at_header(r, request_type, "insert-action")
  data = get_post_data(r)
  con = connect_with_db()
  process_request(con, data)
  close_db_conection!(con)
  return Response("Message of success")
end

```

then call `insert_process_request(r, "user-identifier")` and `insert_process_request(r, "sale-identifier")` as needed, or build other abstractions on top of this. No need to repeat the function body.

A key task in software engineering is figuring out what functions and abstractions you need to avoid copy-and-paste code. (Using macros to automate copy-and-paste code — because that’s what they are here — is generally a second-class solution.)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 12:41pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/10 "2024-09-25T12:41:54Z")

</div>

> [@Ronneesley](#):
>
> At module `B` I should define one by one function

You could define a single function, e.g.

```julia
insert_process_request(r::Request, T::Type) =
       insert_process_request_highorder(r, request_string[T], 
         get_post_data_user, connect_with_db_module_B, 
         process_user_request, close_db_connection_module_B!)

```

where `request_string` is a dictionary mapping request types to strings.

(You could also use other abstractions. If you really want to dispatch on the request types, then the request types could be singleton instances of subtypes of an `AbstractRequestType`, with a method `request_string(request_type)` that returns the string.)

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 25, 2024, 12:42pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/11 "2024-09-25T12:42:35Z")

</div>

@stevengj, the abstract definition of `insert_process_request()` is at module `A`, because I need this at module `B`, `C`, `D`, etc.

So I need pass as argument all functions `get_post_data::Function, connect_with_db::Function, process_request::Function, close_db_conection!::Function` as parameter because they don’t exists at module `A`, only at other modules.

Let me call `A` as `Microservices`, so `B` can be `Ecommerce`, `C` can be `CRM`, etc.

This is because macro are big deal at this context.

So, that solution I proposed at last answer works but is ugly.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 12:46pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/12 "2024-09-25T12:46:09Z")

</div>

> [@Ronneesley](#):
>
> So, that solution I proposed at last answer works but is ugly.

See my second post ([Create dynamic functions with Macro - #10 by stevengj](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/10)) — you still don’t need copy-paste code or macros.

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 25, 2024, 12:56pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/13 "2024-09-25T12:56:16Z")

</div>

@stevengj , I saw your answer… looks good, no so beatiful because I fear the “explosion” of functions passed as argument.

I’ll try this at real context and take my observations.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 25, 2024, 4:41pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/14 "2024-09-25T16:41:24Z")

</div>

> [@Ronneesley](#):
>
> I saw your answer… looks good, no so beatiful because I fear the “explosion” of functions passed as argument.

If you have an explosion of arguments, it’s probably a sign that you need better abstractions.

Abstraction and software design and refactoring is hard, and I can’t give you a magic formula in a few words that will solve everything — there are whole books written about this. But using macros to automate cut-and-paste code is a last resort, rarely needed for this purpose, and certainly not the first thing you should reach for.

One reason is that macros have to be designed very carefully to avoid subtle fragilities arising from scope. Another is that macros usually have less information to work with than ordinary functions — macros only know how things are “spelled”, whereas functions know types and values. See also the thread: [How to warn new users away from metaprogramming](https://discourse.julialang.org/t/how-to-warn-new-users-away-from-metaprogramming/35022)

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [September 25, 2024, 7:39pm UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/15 "2024-09-25T19:39:52Z")

</div>

> [@Ronneesley](#):
>
> If you read at this point, I think do you know what I want. I tried something like this, but it isn’t working:
> 
> ```julia
> macro create(map)
> return esc(Expr(:block, [
> :( function f2(::Type{T}) where T
> return f(T, msg)
> end
> for (T, msg) in map )
> ]...))
> end
> 
> ```

Nobody pointed out your conceptual mistake so far:  
A _macro_ is **not** a _function_ that takes some values and return some expression. A _macro_ runs much earlier in the execution timeline and turns _code_ (i.e. raw expressions) directly into other _code_. As such a _macro_ can never access values of variables or even their types!

Think of a macro as allowing you to define whole new syntax. I don’t think the problem you present here really warrants new syntax. In fact most problems don’t and that’s why writing macros is usually discouraged. For a great usecase for macros you can have a look at e.g. ModelingToolkit.jl or Turing.jl where macros allow an extraordinary efficient way of defining the models/systems.

Of course there are less drastic macros like `@test`, `@info` and similar. They are useful because they represent very common _patterns_ in the code and are essentially just templates and fill in the code the user provided. The problem you describe might warrant a small macro to save the user some typing but providing convenience via macros should not be conflated with actually solving the problem via macros. Aim to first solve the problem normally and then consider a macro to provide a nicer interface (this also makes the macro quite simple to write/read/understand/reason about).

---

<div class="post-metadata">

**Author:** ![Ronneesley](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronneesley/32/11072_2.png) [@Ronneesley](https://discourse.julialang.org/u/Ronneesley)\
**Post date:** [September 26, 2024, 12:33am UTC](https://discourse.julialang.org/t/create-dynamic-functions-with-macro/119824/16 "2024-09-26T00:33:22Z")

</div>

Hello @abraemer ,

That’s exactly the problem, how to create an easy way to code.

Solving the problem is not my problem. The problem is to make it easier to code the necessary functions.

But I can’t create multiple functions based on the macro parameters.
