# Generate type specific code when type is a variable in a loop

**URL:** https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947
**Category:** General Usage
**Tags:** question
**Created:** [September 8, 2022, 3:10pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947 "2022-09-08T15:10:45Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 8, 2022, 3:10pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/1 "2022-09-08T15:10:45Z")

</div>

I have a package where I have a growing amount of types that contain each a specific type of data.  
Each type follows a minimal interface described by :

- A container number `Cnum`
- A description `Cdescription`

Each type `Container<Cnum>` is defined in a separate `<Cnum>.jl` file.  
I do not use parametric types as they do not seem to fit the purpose here (except for the number and description plus a few other things, different types have very different data contents).

My question is : How can I define functions for all of these types wihtout explicitely calling the declaration for each type ?

For instance is there a way to do something in the principle like below, i.e. read the available `Cnum` from a list of files and use this in a loop.  
**Parametric types could be the solution because I totally may have missed something there.**

```julia
# Helper function to extract the type number
read_ds_number_from_file(filename::String) = tryparse(Int64,first(splitext(filename)))
# Retrieve list of files related to each type
const supported_containers = read_cnum_from_files.(readdir(joinpath(@ __DIR__ ,"containers"))) 
# Loop over container identifiers
for cn in supported_containers
    # Get the actual type of a container
    T = eval(Symbol("Container$filenum"))
    # Declare functions based on this type
    cnum(::S) where {S == T} = cn
    description(::S) where {S == T} = eval(Symbol("description$filenum"))
    description(::Val{filenum}) = description(T)
end

```

I have to say what I show here doesn’t feel right, and unsurprisingly fails…

---

<div class="post-metadata">

### Author: ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)
#### Post date: [September 8, 2022, 11:53pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/2 "2022-09-08T23:53:46Z")

</div>

Perhaps a bit more information would help to get replies.

I take it that you have a list of integer values `cn` (read from a file, but that seems incidental). For each `cn` you defined a `struct` (e.g., `Container17` for `cn == 17`).  
The goal is to programatically define _methods_ of a function (say `description`) for each `cn`.

In your example, all the functions need to know about `Container17` is the number `17`. I’m assuming it’s not that simple? But if not, how would the method for `Container17` be constructed from just knowing its name?

But assuming it is that simple, two obvious solutions are:

- store the number 17 in the `struct`
- make it a parametric type `Container{T}` (why not?)

It’s a bit hard to wrap my head around a use case where this pattern would be useful (i.e., defining a method based on the name of the `struct` while `cn` does not play any role other than naming structs in arbitrary order). I think explaining the objective might help.

---

<div class="post-metadata">

### Author: ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)
#### Post date: [September 9, 2022, 12:35am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/3 "2022-09-09T00:35:08Z")

</div>

Define a new abstract type and make all your containers subtypes. Use internal constructors to enforce the correct container number and container description. Then define other functions on the abstract type. Example:

```julia
abstract type MyAbstractContainer end

struct Container1 <: MyAbstractContainer
    cn::Int
    description::String
    # Follow these with data specific to this concrete type
    d1::Matrix{Float64} # for example
    d2::Vector{Int} # etc.

    Container1(d1, d2) = new(1, "I am a Container1", d1, d2) 
end

struct Container2 <: MyAbstractContainer
    cn::Int
    description::String
    # Follow these with data specific to this concrete type
    f1::Vector{Float64} # for example
    f2::Int # etc.

    
    Container2(f1, f2) = new(2, "I am a Container2", f1, f2) 
end

cnum(x::MyAbstractContainer) = x.cn
description(x::MyAbstractContainer) = x.description

```

With these definitions in place, you can do the following:

```julia
julia> c2 = Container2([1.,3.], 4)
Container2(2, "I am a Container2", [1.0, 3.0], 4)

julia> description(c2)
"I am a Container2"

julia> cnum(c2)
2

```

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 8:15am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/4 "2022-09-09T08:15:11Z")

</div>

> [@hendri54](#):
>
> I take it that you have a list of integer values `cn` (read from a file, but that seems incidental). For each `cn` you defined a `struct` (e.g., `Container17` for `cn == 17`).  
> The goal is to programatically define _methods_ of a function (say `description`) for each `cn`.

Yes, you summed it up very well.

> [@hendri54](#):
>
> In your example, all the functions need to know about `Container17` is the number `17`. I’m assuming it’s not that simple? But if not, how would the method for `Container17` be constructed from just knowing its name?

Yes, the important part is the number, because this number totally defines the data structure of interest. For instance, in file `17.jl` I have a `const description17 = "Some description 17"` because the description is specific to the type, not to each instance of the type, a bit like what would be in a docstring. The same goes for the number, I don’t want to store this kind of info in each instance, which may be numerous.

> [@hendri54](#):
>
> make it a parametric type `Container{T}` (why not?)

This is probably a good way to do it, but I’m not sure I can do e.g. `description(::Container{T}) where {T == 17} = "Some description 17"` can I ?

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 8:16am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/5 "2022-09-09T08:16:47Z")

</div>

Thanks for the proposal, but it does not fit my purpose. The goal is not to attach the info in each instance, but to the type itself. That would result in a lot of data duplication.

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [September 9, 2022, 9:13am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/6 "2022-09-09T09:13:21Z")

</div>

This works though:

```julia
julia> struct Container{T} end

julia> description(::Container{T}) where T = "Some description $T"
description (generic function with 1 method)

julia> description(Container{17}())
"Some description 17"

```

But you can do it more flexibly in a way similar to what you tried in your original post if you get the syntax right:

```julia
julia> spec = Dict(1 => "description of the first kind of container",
                   2 => "second kind of container")
Dict{Int64, String} with 2 entries:
  2 => "second kind of container"
  1 => "description of the first kind of container"

julia> for (i, desc) in spec
           @eval description(::Container{$i}) = $desc
       end

julia> description(Container{1}())
"description of the first kind of container"

julia> description(Container{2}())
"second kind of container"

```

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [September 9, 2022, 9:51am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/7 "2022-09-09T09:51:50Z")

</div>

Maybe this will give you some inspiration.

```julia
julia> macro add_description(num)
           T = esc(Symbol("Container$num"))
           f = esc(:description)
           desc_str = Symbol("description$num")
           quote
               struct $T end
               $f(::Type{$T}) = $desc_str
               $f(::Val{$num}) = $desc_str
           end
       end
@add_description (macro with 1 method)

julia> const description8 = "Eight is the best" "Eight is the best"

julia> const description42 = "Answer to the Ultimate Question of Life, the Universe, and Everything"
"Answer to the Ultimate Question of Life, the Universe, and Everything"

julia> @add_description(8)
description (generic function with 2 methods)

julia> @add_description(42)
description (generic function with 4 methods)

julia> description(Container8)
"Eight is the best"

julia> description(Container42)
"Answer to the Ultimate Question of Life, the Universe, and Everything"

julia> description(Val(8))
"Eight is the best"

julia> description(Val(42))
"Answer to the Ultimate Question of Life, the Universe, and Everything"

```

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 10:39am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/8 "2022-09-09T10:39:44Z")

</div>

> [@GunnarFarneback](#):
>
> `description(::Container{T}) where T = "Some description $T"`

Sorry, I have misled you with this example, the description can be very different between containers.

Your second example is getting very close !

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 10:41am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/9 "2022-09-09T10:41:09Z")

</div>

This is pretty much what my intent was, but I’ve never used julia macros before. Thanks for this example !  
I just have a comment : what is the purpose of the `struct $T end` ?

---

<div class="post-metadata">

### Author: ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)
#### Post date: [September 9, 2022, 11:46am UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/10 "2022-09-09T11:46:40Z")

</div>

The part that I’m not seeing is: Usually one would just do

```julia
struct Container17
  [fields]
end

description(::Container17) = "Description for seventeen"

```

Isn’t that the easiest approach? How is

```julia
const description17 = "Description seventeen"

```

plus a macro easier?

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 12:20pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/11 "2022-09-09T12:20:07Z")

</div>

Yes, usually that would be enough, here the description is used as an example, but this is an oversimplification of my program. In the end, the macro only writes the code at your place…

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [September 9, 2022, 12:42pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/12 "2022-09-09T12:42:16Z")

</div>

This is not really something I would use a macro for but if it works for you, fine.

However, be aware that it relies on being called with literals. Doing

```julia
for i in (8, 42)
    @add_description(i)
end

```

is not at all the same thing as

```julia
@add_description(8)
@add_description(42)

```

This is one way to see the difference:

```julia
julia> @macroexpand @add_description(8)
quote
    #= REPL[19]:6 =#
    struct Container8
        #= REPL[19]:6 =#
    end
    #= REPL[19]:7 =#
    description(::Main.Type{Container8}) = begin
            #= REPL[19]:7 =#
            Main.description8
        end
    #= REPL[19]:8 =#
    description(::Main.Val{8}) = begin
            #= REPL[19]:8 =#
            Main.description8
        end
end

julia> i = 8; @macroexpand @add_description(i)
quote
    #= REPL[19]:6 =#
    struct Containeri
        #= REPL[19]:6 =#
    end
    #= REPL[19]:7 =#
    description(::Main.Type{Containeri}) = begin
            #= REPL[19]:7 =#
            Main.descriptioni
        end
    #= REPL[19]:8 =#
    description(::Main.Val{Main.i}) = begin
            #= REPL[19]:8 =#
            Main.descriptioni
        end
end

```

---

<div class="post-metadata">

### Author: ![BambOoxX](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bambooxx/32/22179_2.png) [@BambOoxX](https://discourse.julialang.org/u/BambOoxX)
#### Post date: [September 9, 2022, 12:58pm UTC](https://discourse.julialang.org/t/generate-type-specific-code-when-type-is-a-variable-in-a-loop/86947/13 "2022-09-09T12:58:35Z")

</div>

This is indeed a difference, I noticed it too, but your warning and example are very much welcome.
