# Passing boolean settings to module to parse fast kernels via macros

**URL:** <https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702>\
**Category:** Performance\
**Created:** [September 24, 2021, 2:50pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702 "2021-09-24T14:50:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Chiil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chiil/32/27474_2.png) [@Chiil](https://discourse.julialang.org/u/Chiil)\
**Post date:** [September 24, 2021, 2:50pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/1 "2021-09-24T14:50:22Z")

</div>

I have a module that builds high performance kernels, based on user settings. I would like to construct them using settings that are provided by the user that imports the `Kernels` module. What would be the most logical way to pass the variables that I now set as global constants from the user side to the module, such that the settings are known at the time the macro is parsed? I am new to Julia and probably overlook something obvious, or do something in a non-Julian way. This is a highly simplified minimal working example of my code:

```julia
module Kernels

export kernel

# These should be removed.
const do_advection = true
const do_diffusion = false
const do_source = true

macro make_kernel()
    ex_rhs = :( 0 )
    if do_advection
        ex_rhs = :($ex_rhs .+ 1)
    end
    if do_diffusion
        ex_rhs = :($ex_rhs .+ 2)
    end
    if do_source
        ex_rhs = :($ex_rhs .+ 4)
    end

    ex = :( a .+= $ex_rhs )

    println(ex)
    return esc(ex)
end

function kernel(a)
    @make_kernel
end

end

using .Kernels

# I would like to be able to set the settings here.

a = zeros(10)
kernel(a)
println(a)

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [September 24, 2021, 4:54pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/2 "2021-09-24T16:54:01Z")

</div>

Macros are expanded during parsing, so if you want to make them user configurable I’d pass any custom settings you wish to use in front of the expression you want the macro to operate on as a `key=val` expression.

An alternative would be (if you want the setting to be global) to use a `Ref` instead of a plain value.

---

<div class="post-metadata">

**Author:** ![Chiil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chiil/32/27474_2.png) [@Chiil](https://discourse.julialang.org/u/Chiil)\
**Post date:** [September 24, 2021, 5:46pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/3 "2021-09-24T17:46:45Z")

</div>

But how? I have followed your suggestion, yet I do not know how to get my settings into the macro in the code below:

```julia
module Kernels

export kernel

macro make_kernel(do_advection, do_diffusion, do_source)
    ex_rhs = :( 0 )
    if do_advection
        ex_rhs = :($ex_rhs .+ 1)
    end
    if do_diffusion
        ex_rhs = :($ex_rhs .+ 2)
    end
    if do_source
        ex_rhs = :($ex_rhs .+ 4)
    end

    ex = :( a .+= $ex_rhs )

    println(ex)
    return esc(ex)
end

function kernel(a, do_advection, do_diffusion, do_source)
    @make_kernel(do_advection, do_diffusion, do_source)
end

end

using .Kernels

const do_advection = true
const do_diffusion = true
const do_source = true

a = zeros(10)
kernel(a, do_advection, do_diffusion, do_source)
println(a)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 24, 2021, 5:55pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/4 "2021-09-24T17:55:31Z")

</div>

Most commonly just pass the parameters as parameters to the function (do not use macros) for that:

```julia
julia> Base.@kwdef struct Parameters
           do_diffusion::Bool = true
           do_source::Bool = true
       end
Parameters

julia> function make_kernel(;p=Parameters())
           if p.do_diffusion
               println("do diffusion")
           end
           if p.do_source
               println("do source")
           end
       end
make_kernel (generic function with 1 method)

julia> make_kernel() # default parameters
do diffusion
do source

julia> make_kernel(p=Parameters(do_diffusion=false))
do source

```

---

<div class="post-metadata">

**Author:** ![Chiil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chiil/32/27474_2.png) [@Chiil](https://discourse.julialang.org/u/Chiil)\
**Post date:** [September 24, 2021, 6:12pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/5 "2021-09-24T18:12:10Z")

</div>

How can I make a single line statement with that solution? Can you show how my example would look like? In the actual use case the statement is inside a triple nested loop. Following your solution, it would end up with three separate loops, and this is why I am using macros.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 24, 2021, 6:22pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/6 "2021-09-24T18:22:37Z")

</div>

If what you want is to elimitate the conditional inside an inner loop, you may want to use multiple dispatch. For example:

```julia
julia> function my_kernel(;p=Parameters())
           for i in 1:2
               for j in 1:2
                   inner_function(Val(p.do_source),Val(p.do_diffusion))
               end
           end
       end
my_kernel (generic function with 2 methods)

julia> inner_function(::Val{true},::Val{true}) = println("do both")
inner_function (generic function with 1 method)

julia> inner_function(::Val{false},::Val{true}) = println("do diffusion")
inner_function (generic function with 2 methods)

julia> inner_function(::Val{true},::Val{false}) = println("do source")
inner_function (generic function with 3 methods)

julia> inner_function(::Val{false},::Val{false}) = println("do nothing")
inner_function (generic function with 4 methods)

julia> Base.@kwdef struct Parameters
           do_diffusion::Bool = true
           do_source::Bool = true
       end
Parameters

julia> my_kernel()
do both
do both
do both
do both

julia> my_kernel(p=Parameters(do_source=false))
do diffusion
do diffusion
do diffusion
do diffusion

julia> my_kernel(p=Parameters(do_source=true,do_diffusion=false))
do source
do source
do source
do source

julia> my_kernel(p=Parameters(do_source=false,do_diffusion=false))
do nothing
do nothing
do nothing
do nothing

```

This eliminates the conditional inside the loop.

I’m not sure if this is the best solution for your problem, though, probably more information would be needed for actually suggesting something more specific.

(to really get this to be performant (more than just adding a conditional), you would need to somehow pass the values as parameters to the `my_kernel` function. Probably add a function barrier there).

---

<div class="post-metadata">

**Author:** ![Chiil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chiil/32/27474_2.png) [@Chiil](https://discourse.julialang.org/u/Chiil)\
**Post date:** [September 24, 2021, 6:37pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/7 "2021-09-24T18:37:29Z")

</div>

The actual use case is here: [https://github.com/Chiil/MicroHH.jl/blob/main/src/Dynamics.jl#L43](https://github.com/Chiil/MicroHH.jl/blob/main/src/Dynamics.jl#L43). I made a macro-based finite difference stencil generator, but at the moment all processes are standard on. I wanted to make this more sophisticated by letting the user decide which terms are included in the expression, without losing performance. Given that I have four options at the moment, that would mean 2^4 functions to be defined following your solution, which is doable, but at the same time it would be great if that effort could be prevented.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 24, 2021, 6:53pm UTC](https://discourse.julialang.org/t/passing-boolean-settings-to-module-to-parse-fast-kernels-via-macros/68702/8 "2021-09-24T18:53:27Z")

</div>

My two cents is that then you can use a macro to create all the inner functions, instead of making that dependent on the user choices. But others may know better if that is a good alternative.
