# Maintainability: Best way to have two versions of the same function with minor differences

**URL:** https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453
**Category:** General Usage
**Tags:** packages, multiple-dispatch
**Created:** [November 9, 2024, 5:12pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453 "2024-11-09T17:12:12Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [November 9, 2024, 5:12pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/1 "2024-11-09T17:12:12Z")

</div>

Say I have two usecases for a function. One logs the result of each iteration and is parallelized using `Polyester.@batch`, the other only needs to return the final result and uses `Threads.@threads`. Performance is top priority in the second case, but “only” very important in the first case (with the logs).

Also, the choice is known at “compile time”, ie when the package is loaded.

NB: The real code has a bunch of logging events, so the code becomes less readable in that case:

```julia
using BenchmarkTools, Distributions, Polyester, .Threads

function example!(dat, dlog)
    @batch for i in 1:50
        flag = rand(Bernoulli(0.25))
        if flag
            idx = rand(1:10)
            dat[idx] += 1
            dlog[i] = idx
        end
    end
    return dat, dlog
end

function example!(dat)
    @threads for i in 1:50
        flag = rand(Bernoulli(0.25))
        if flag
            idx = rand(1:10)
            dat[idx] += 1
        end
    end
    return dat
end

dat = fill(0, 10); dlog = fill(0, 50);
example!(dat, dlog)

dat = fill(0, 10); dlog = fill(0, 50);
example!(dat)

```

Is there a way to do this without needing to maintain two separate versions, or adding a bunch of if-statements?

Maybe if a global const is set, `@batch` is chosen then `dlog` gets updated each time `dat` is modified?

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [November 9, 2024, 9:48pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/2 "2024-11-09T21:48:36Z")

</div>

Perhaps something like this:

```julia
                                                                               
@inline function _example2!(dat, i, ::Val{dolog}, dlog=nothing) where dolog     
    flag = rand(Bernoulli(0.25))                                                
    if flag                                                                     
        idx = rand(1:10)                                                        
        dat[idx] += 1                                                           
        dolog && (dlog[i] = idx)                                              
    end                                                                         
    return dolog ? (dat, dlog) : dat                                            
end                                                                             
                                                                                
function example2!(dat)                                                         
    @threads for i in 1:50                                                      
        _example2!(dat, i, Val(false))                                          
    end                                                                         
end                                                                             
                                                                                
function example2!(dat, dlog)                                                   
    @batch for i in 1:50                                                        
        _example2!(dat, i, Val(true), dlog)                                     
    end                                                                         
end                                                                             

```

---

<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: [November 9, 2024, 9:50pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/3 "2024-11-09T21:50:11Z")

</div>

I think this could be a good application for Preferences.jl. Using this mechanism the user can configure (statically) what the library does.

---

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [November 10, 2024, 3:30pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/4 "2024-11-10T15:30:20Z")

</div>

This helps for the parallel library but still its cluttering the code up with lines about the log. Is there expected to be a performance benefit from doing it this way vs wrapping the log lines in if-statements?

---

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [November 10, 2024, 3:31pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/5 "2024-11-10T15:31:24Z")

</div>

I keep coming across this package for a number of reasons, so will definitely be checking it out.

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [November 10, 2024, 3:36pm UTC](https://discourse.julialang.org/t/maintainability-best-way-to-have-two-versions-of-the-same-function-with-minor-differences/122453/6 "2024-11-10T15:36:44Z")

</div>

> [@Tetrakai](#):
>
> This helps for the parallel library but still its cluttering the code up with lines about the log. Is there expected to be a performance benefit from doing it this way vs wrapping the log lines in if-statements?

The `dolog` is a compile time type parameter. So if `_example2!` is called with `Val(false)`, the `dolog && ...` lines are optimized away, whereas if you call it with `Val(true)`, the test is optimized away, so only an unconditional `dlog[i] = idx` remains. For tight loops a test can destroy performance, preventing vectorization, stalling the pipeline and so on, so it can be beneficial to avoid the tests altogether in this way.
