Suppose I have several parametric wrapper types, like so (toy example):

```
abstract type AbsWrapper end
struct WrapperA{T <: Real} <: AbsWrapper
x::T
end
struct WrapperB{T <: Real} <: AbsWrapper
x::T
end
```

I’d like to write converter functions that convert instances of an `AbsWrapper`

to a “similarly typed” value wrapping a `Float64`

. E.g.

`to_float64_form(w::WrapperA) = WrapperA(Float64(w.x))`

Great, this works! And if I have just two wrapper types and one conversion, two one-line functions are all I need. But suppose I have types `WrapperA`

, `WrapperB`

, `WrapperC`

, etc., and I want to write converters `to_float64_form`

, `to_float32_form`

, `to_rational_form`

,… Then there are (number of types) * (number of conversion) functions to write, and the source code gets repetitive. This can be solved (or at least mitigated?) with `@eval`

, e.g.

```
for T in [WrapperA, WrapperB]
@eval to_float64_form(val::$T) = $T(Float64(val.x))
end
```

But I’m not sure if `@eval`

is necessary here. This feels like a use case that should be solvable with a single parametric method, but I’m struggling. Is `@eval`

the preferred way to handle this, and if not what is best practice?