# Defining functions with multiple methods inside a function

**URL:** <https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768>\
**Category:** General Usage\
**Created:** [December 29, 2021, 5:11pm UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768 "2021-12-29T17:11:26Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [December 29, 2021, 5:11pm UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768/1 "2021-12-29T17:11:27Z")

</div>

I am writing a data type that is, essentially, a wrapper for a function, which will be accessed as a functor, but the arguments for the outside struct constructor determine the nature of the function.

(As an irrelevant aside, the goal is to be able to populate an array with “data generating process” data structures describing stochastic processes. The array of types will support estimation of parameters (via indirect inference / simulated method of moments and other methods); it will support calibration of subsets of parameters; and it will support counterfactual simulations, where exogenous variables are set to choice values. Frequently, when people estimate this sort of model, they put parameters and variables in arrays with no way to keep track of which position represent which variable/parameter except through mental effort. Requiring mental effort to keep track of this sort of thing invites serious and undetectable semantic errors).

The struct looks like:

```julia
struct DataGeneratingProcess <: AbstractDataGeneratingProcess
    LHS_varname::Union{Symbol, Vector{Symbol}}
    RHS_varnames::Vector{Symbol}
    parameter_names::Vector{Symbol}
    func::Function
    func_print::String
end

```

The outer constructor below is a work-in progress and I can’t get it to do what I want it to do.  
The function \_f( . ) need to have a method that accept a pair of NamedTuple’s, where the type signature of the NamedTuple’s depend on arguments of the constructor. Then I want to add other methods to this function. Ignoring the wisdom of this general approach, how do I execute on this?

I have tried many different ways to execute on this, but I either can’t add methods to the function or I can’t metaprogram the type signature of the function.

```julia
function DataGeneratingProcess(lhs::Union{Symbol, Vector{Symbol}}, rhs::Vector{Symbol}, parameter_names::Vector{Symbol}, eqn::String)
  

    #rhs = sort(rhs; rev=true)
    #parameter_names = sort(parameter_names; rev=true)

    RhsType = _vec_to_nt(rhs)
    ParmType = _vec_to_nt(parameter_names)
    parsed_eqn = split(eqn, "=")[2] #TODO: better parsing than relying on spaces.

    for v in rhs
        parsed_eqn = replace(parsed_eqn, " " * string(v) * " " => " inner_rhs[:$v] ")
    end

    for v in parameter_names
        parsed_eqn = replace(parsed_eqn, " " * string(v) * " " => " inner_params[:$v] ")
    end

    #_f(inner_rhs::Union{Tuple, AbstractArray}, inner_params::Union{Tuple, AbstractArray}) = _f(zip(rhs, inner_rhs), zip(parameter_names, inner_params))        

    # let RhsType=RhsType, ParmType=ParmType, parsed_eqn=parsed_eqn, parameter_names, rhs
    # func_string = """
    # function _f(inner_rhs::$RhsType, inner_params::$ParmType)        
    # return $parsed_eqn
    # end
    # """
    # print(func_string)

    # func_string |> Meta.parse |> Meta.eval
    # 
    # end
    func_string = """
            global function _f(inner_rhs::$RhsType, inner_params::$ParmType)        
                return $parsed_eqn
            end
        """

    #print(func_string)
    func_string |> Meta.parse |> Meta.eval

    function _f(rhs_var::AbstractVector{N} where N <: Number, param_vals::AbstractVector{N} where N <: Number)
        return rhs_var
    end

    function _f()
        return nothing
    end

   

    return DataGeneratingProcess(lhs, rhs, parameter_names, _f, eqn)

end

```

The below should run but does not. I can either get a single method function generated through metaprogramming that can evaluate on the named tuple or I can get a function with multiple methods that can evaluate on the pair of arrays but not one that can run on the NamedTuple generated type-signature.

```julia
dgp1 = DataGeneratingProcess(:y, [:x, :w], [:β, :γ],"y = β * x + γ * w ")

dgp1.func((x=1,w=1), (β=1, γ=3))

dgp1.func([1,2], [1, 2])

```

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [December 29, 2021, 6:48pm UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768/2 "2021-12-29T18:48:04Z")

</div>

I didn’t read through your whole code, but two things to keep in mind

1. Don’t use `Meta.parse` and don’t use `eval`. If you are using those, something is wrong.
2. Julia is not object oriented. Rather, store your information in structs and define methods which _take in_ those structs, but the structs themselves should generally not be callable.

Remember that functions are first order in Julia and can be passed around very easily. You probably want to be passing a function around rather than a string which contains an operation.

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [December 29, 2021, 10:39pm UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768/3 "2021-12-29T22:39:13Z")

</div>

> 1. Don’t use `Meta.parse` and don’t use `eval` . If you are using those, something is wrong.

That’s usually good advice but I am pretty sure I need metaprogramming for what I want to do.

> 1. Julia is not object oriented  
> I am aware of that and I generally separate data from functions. But this use case does not want generic functions (see below).

Long run goal is use syntax similar to @formual(y ~ x + w).

Something like:

```julia
@parameters β, γ, δ, α, σ
@variables y, x, w, ϵ, 
structural_model = [@dgp(y = x*β + w*γ + σ*ϵ), 
                    @dgp(x = z*δ + α*ϵ), 
                    @shock(ϵ ~ Normal(0,1))]
parameter_values = ParameterValues((β=1.0, γ=1.3, δ=.5, α=2.4, σ=.2))

N=100
df = DataFrame(w=rand(N, Normal(0,1)), z=rand(N, Normal(0,1)))

simulated_df = sim(structural_model, parameter_values, df)

```

where simulated\_df was simulated according to the @dgp expressions plugging in data from the dataframe and parameter values.

A syntax that would allow this would be extremely helpful – it would allow shorter, more readable, easier to debug code.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [December 30, 2021, 12:34am UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768/4 "2021-12-30T00:34:42Z")

</div>

> [@croberts](#):
>
> That’s usually good advice but I am pretty sure I need metaprogramming for what I want to do.

What you want might need metaprogramming, but `eval` and `Meta.parse` are not metaprogramming. Metaprogramming operates on already-parsed Julia expressions, _not_ strings.

Take a look at StatsModels.jl and `@formula`. It doesn’t use `eval` or `Meta.parse`.

---

<div class="post-metadata">

**Author:** ![croberts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/croberts/32/9465_2.png) [@croberts](https://discourse.julialang.org/u/croberts)\
**Post date:** [December 30, 2021, 3:55pm UTC](https://discourse.julialang.org/t/defining-functions-with-multiple-methods-inside-a-function/73768/5 "2021-12-30T15:55:24Z")

</div>

Thanks for the tip!
