# Type With Variable Number Of Parameters

**URL:** <https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409>\
**Category:** New to Julia\
**Created:** [February 28, 2025, 3:06am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409 "2025-02-28T03:06:26Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [February 28, 2025, 3:06am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/1 "2025-02-28T03:06:27Z")

</div>

Hello Julians,

I am trying to define a parametric type `MyType{T1,T2,T3,...}` where the number of `Ti`’s may vary according to constructor’s `arg`… I’ve done something similar to:

```julia
struct MyType{T}
  m::Union{T,Tuple{Vararg{T}}} where T
  MyType(a::A...) where A = new{typeof(a)}(a)
end

```

…but it doesn’t really do what I need. Any suggestion?

Regards.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 28, 2025, 3:23am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/2 "2025-02-28T03:23:56Z")

</div>

> [@Soel](#):
>
> a parametric type `MyType{T1,T2,T3,...}` where the number of `Ti`’s may vary according to constructor’s `arg`

Not possible.

> [@Soel](#):
>
> `Tuple{Vararg{T}}`

But one parameter can subtype `Tuple`, thus be any length. You won’t get extra parameter names to annotate fields with, but it doesn’t seem like you need it anyway. This will have a different concrete type for a different tuple length:

```julia
julia> struct MyType{T, S<:Tuple{T,T,Vararg{T}}} # tuple >= 2
         m::Union{T, S}
         MyType(a::A...) where A = new{A, typeof(a)}(a)
       end

julia> MyType(1,2,3,4)
MyType{Int64, NTuple{4, Int64}}((1, 2, 3, 4))

julia> MyType(1,2)
MyType{Int64, Tuple{Int64, Int64}}((1, 2))

julia> MyType(1)
ERROR: TypeError: in MyType, in S, expected S<:Tuple{Int64, Int64, Vararg{Int64}}, got Type{Tuple{Int64}}

```

Not sure how you intend the 1-argument scenario to infer the alternate tuple length though. Might be easier to go for a 1-tuple instead, just store tuples in `m`.

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [February 28, 2025, 3:52am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/3 "2025-02-28T03:52:20Z")

</div>

Thank you for your reply,

The usage of `MyType` will be 90% with a single object in field `m` and I already have a lot of code implemented with `MyType` having `m` as a single object, I don’t want to go and change hundreds of lines… I’m just adding the ability to have multiple models stored in `m`… having `MyType{A,B,C,...}` would’ve been cool though!

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [February 28, 2025, 8:30am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/4 "2025-02-28T08:30:14Z")

</div>

Would an alternative thought maybe be to have the storage “the other way around”, so a `Vector[MyType]` (or tuple) instead of a tuple “inside”?  
That would be basically broadcasting in the functions then (or dispatch on the vector my type case, depending on what your functions do.

Of oourse that depends a lot on the actual situation, but maybe keeping the `MyType` a “simpler structure” might be something that could be nice.

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 4, 2025, 9:01pm UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/5 "2025-03-04T21:01:14Z")

</div>

Yeah, but implemented it this way because some models (financial) come with the “parameters”, the very model creates its specific framework, its specific world… It was to enforce those ideas…  
But yeah, the struct is simple, lightweight… I wanted it to dispatch… it does so with `MyType{Tuple{A,B,C}}`…

Thanks.

---

<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:** [March 6, 2025, 1:31pm UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/6 "2025-03-06T13:31:13Z")

</div>

I know it’s too late now, so I’m sorry to Monday Morning Quarterback you, but the “I’m accessing a property so I can’t change it’s behavior without doing a major refactor” problem is why it’s recommended to use accessor functions.

```julia
struct MyType{T}
    m::T
end

get_model(x::MyType) = x.m

function f(x)
    y = get_model(x)
    # do something with singleton y
end

# oops I realized that sometimes m is a tuple
# which will get confusing.

function get_model(::MyType{<:Tuple})
    # setup default behavior
    # maybe error to fail loudly
    # maybe just return the first model
end

#always return a tuple
get_models(x::MyType) = (x.m,)
get_models(x::MyType{<:Tuple) = x.m

```

This makes it easier to refactor because now you can search for reference to the function instead of trying to CTRL+F for `.m`.

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 7, 2025, 7:03am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/7 "2025-03-07T07:03:21Z")

</div>

Thank you sir for your reply, accessors functions are useful indeed.  
By the way (it’s kinda another question), what about the speed of `x.m` compared to `getfield(x,:m)` ? Everywhere in my code (and I have 30K+ LOC so far) I prefer the later syntax and folks find it verbose… I do it because of the speed; `getfield` is a heck faster (at least for every _benchmark_ I have run so far)!

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 7, 2025, 7:15am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/8 "2025-03-07T07:15:46Z")

</div>

> [@Soel](#):
>
> what about the speed of `x.m` compared to `getfield(x,:m)` ?

There shouldn’t be a difference. The little indirection of accessors or `getproperty` (what dot syntax lowers to) can be handled at compile-time.

---

<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:** [March 7, 2025, 11:36am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/9 "2025-03-07T11:36:48Z")

</div>

The Julia compiler will calculate anything it can prove is a constant and just insert the result, like @Benny said.

Can you post a benchmark where you are seeing a difference?

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [March 7, 2025, 4:04pm UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/10 "2025-03-07T16:04:32Z")

</div>

For anyone interested in a type like this its relatively easy to just wrap a `NamedTuple`, and get a totally flexible struct.

You can copy Extents.jl [GitHub - rafaqz/Extents.jl: A shared Extent object for Julia spatial data, with DE-9IM spatial predicates](https://github.com/rafaqz/Extents.jl) for a simple template.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 7, 2025, 11:34pm UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/11 "2025-03-07T23:34:25Z")

</div>

> [@Soel](#):
>
> I already have a lot of code implemented with `MyType` having `m` as a single object, I don’t want to go and change hundreds of lines … I’m just adding the ability to have multiple models stored in `m`

> [@Soel](#):
>
> some models (financial) come with the “parameters”, the very model creates its specific framework … I wanted it to dispatch

It’s worth pointing out this is a stage where design can be reconsidered, which is easier than having to refactor later, and that in general, the language’s design isn’t a template for how anything is organized. Just as type parameters vary the field types or add limited `isbits` type information to parametric types rather than cleanly correspond to “parameters” in other contexts or the general sense, there’s no inherent reasons for all models to be grouped under a parametric type, for a model to be represented by one type, or even for different models to have different types. For example, if there are a fixed number of models, then it would be cleaner to incorporate model-parameter names as varying fields of distinct types rather than the same set of fields of a parametric type, and if they need to dispatch to entirely separate methods instead of sharing any, there isn’t a need for a supertype. What’s best depends on the context, just use your best judgment and accept occasional refactoring.

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 8:27am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/12 "2025-03-09T08:27:08Z")

</div>

Here’s an example, the statistical significance of the difference might be argued…

```julia
julia> struct JL
         a::Real
         b::Real
         c::Real
       end

julia> a=JL(rand(3)...);

julia> @benchmark a.a
BenchmarkTools.Trial: 10000 samples with 996 evaluations per sample.
 Range (min … max): 23.972 ns … 32.499 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 24.185 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 24.198 ns ± 0.233 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
...

julia> @benchmark getfield(a,:a)
BenchmarkTools.Trial: 10000 samples with 997 evaluations per sample.
 Range (min … max): 19.556 ns … 45.117 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 19.566 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 19.650 ns ± 0.939 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
...

```

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 8:38am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/13 "2025-03-09T08:38:42Z")

</div>

Yes, thank you. But for what I am doing, I think it’s better to have it like that. It’s a Monte-Carlo facility… You feed it with some models (I guess under the hood it’s just a pointer to those models) and when you need to price the financial instrument, you just use the (hugely) overloaded pricing method! Models need to be categorized (volatility models…) though I’ll see what best fits everything… Everyday we have to refine the ideas…

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 9, 2025, 8:45am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/14 "2025-03-09T08:45:07Z")

</div>

Your benchmark is getting thrown off by referencing a global variable `a` rather than taking it as an argument, which is more typical for non-`const` variables for performance reasons. `$`-interpolation does the latter.

```julia
julia> @benchmark $a.a
BenchmarkTools.Trial: 10000 samples with 1000 evaluations per sample.
 Range (min … max): 1.800 ns … 92.400 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 1.900 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 1.892 ns ± 1.182 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  ▅ █
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂ ▂
  1.8 ns Histogram: frequency by time 2 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark getfield($a, :a)
BenchmarkTools.Trial: 10000 samples with 1000 evaluations per sample.
 Range (min … max): 1.800 ns … 42.100 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 1.800 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 1.849 ns ± 0.693 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▇ ▂
  1.8 ns Histogram: frequency by time 1.9 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 8:51am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/15 "2025-03-09T08:51:38Z")

</div>

To be honest, with the examples I first tried, there was no difference… Btw, I benchmarked real objects in my package… I have to find a good example for it to be reproducible… After all, y’all are Julia experts, if you think that `MyType.a` is the equivalent to `getfield(MyType,:a)` (performance-wise) you have a good reason to think so… I’ll look at the implementation though…

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 8:55am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/16 "2025-03-09T08:55:28Z")

</div>

…thank you for the interpolation hint by the way… haven’t realized it…

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 9, 2025, 8:59am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/17 "2025-03-09T08:59:04Z")

</div>

I was about to comment on the implementation. Your benchmark isn’t “wrong”, it’s a real phenomenon that BenchmarkTools is measuring. My benchmark would be relevant to code that looks like this:

```julia
x = (a=1,)
geta(y) = y.a # named y for disambiguation, could be local x instead

```

Your benchmark would be relevant to code that looks like this:

```julia
x = (a=1,)
geta() = x.a

```

In the latter case, the compiler can’t leverage the input types of the method call to optimize, instead it must assume that the referenced `x` can be of ANY type. `x.a` lowers to `getproperty(x, :a)` when the method definition is parsed (long before the compiler gets involved), and that is implemented in v1.11.3 as:

```julia
getproperty(x::Type, f::Symbol) = (@inline; getfield(x, f))

```

So your benchmark shows that `getproperty`’s extra indirection adds a bit more time to the underlying `getfield` when the compiler can’t optimize. The Performance Tips discourage referencing non-`const` global variables for this reason, though it has its uses.

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 9:05am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/18 "2025-03-09T09:05:58Z")

</div>

…so as a rule of thumb one is better off with `getfield`!

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 9, 2025, 9:14am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/19 "2025-03-09T09:14:16Z")

</div>

Well, no, it makes no difference when the compiler handles it, so the more concise dot syntax will be nicer to read and write. Even in the case you’re working on non-`const` globals or something else the compiler can’t infer, saving those few nanoseconds out of dozens would only be significant for field accesses in a hot loop, and there are much more important ways to optimize (you probably want to aim for 1.8ns instead of 19.6ns, and outside of loops as much as possible).

---

<div class="post-metadata">

**Author:** ![Soel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soel/32/214997_2.png) [@Soel](https://discourse.julialang.org/u/Soel)\
**Post date:** [March 9, 2025, 9:16am UTC](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409/20 "2025-03-09T09:16:54Z")

</div>

Haha, well OK.

[Next page](https://discourse.julialang.org/t/type-with-variable-number-of-parameters/126409.md?page=2)
