# Modifying TypeVar that will have a concrete value?

**URL:** https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149
**Category:** General Usage
**Tags:** question
**Created:** [November 13, 2023, 1:40pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149 "2023-11-13T13:40:45Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![jecs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jecs/32/1781_2.png) [@jecs](https://discourse.julialang.org/u/jecs)
#### Post date: [November 13, 2023, 1:40pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/1 "2023-11-13T13:40:46Z")

</div>

Say I have an abstract type that is parameterized on a `TypeVar` that will have a concrete integer value.

```julia
abstract type A{N} end

```

I have a struct `B` where I’d like to subtype `A` but where I modify the `TypeVar` that is used.

```julia
struct B{M} <: A{M+1}
...
end

```

Adding 1 is arbitrary. I might also want to multiply `M` or something like that.

Is it possible to replicate this behavior somehow? Doing it directly does not work, since you can’t constrain `M` to be of a particular type, like you would do in C++.

---

<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: [November 13, 2023, 5:50pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/2 "2023-11-13T17:50:33Z")

</div>

That’s impossible because subtyping and field types need to be unchanging, but methods aren’t.\* Part of it is `M` not being constrained, so `+(M, 1)` can’t be dispatched in advance. But even if you could somehow specify `M::ConcreteType`, there’s no proof that the method for the call `+(::ConcreteType, ::Int)` won’t change, even if you are sure it _shouldn’t_ change like in the case of `+(::Int, ::Int)`. Imagine that you had `B{3} <: A{4}`, but Big Brother tells you `3+1 == 5`; `B{3} <: A{5}` is an unfeasible change to make across all method tables and compiled code.

I think the closest you can do is `struct B{M, N} <: A{N} end`, throw an error in the inner constructor when `N == M+1` is violated, and try to make sure it’s made true in other constructors e.g. `B{M}() where M = B{M, M+1}()`. Note that this doesn’t constrain `N == M+1` for the type itself; with enough effort you can change what the constructors do, and the type parameters won’t need to (and can’t) change to accommodate the constructors’ different constraints.

> **\*Example of constraint in changeable inner constructor**
>
> ```julia
> julia> abstract type A{N} end
> 
> julia> struct B{M, N} <: A{N}
> function B{M, N}() where {M, N}
> if !(N == M+1) throw("blah") end
> new{M,N}()
> end
> end
> 
> julia> B{3,5} # type itself not constrained
> B{3, 5}
> 
> julia> B{3,5}() # but constructor constrains instantiation
> ERROR: "blah"
> Stacktrace:
> [1] B{3, 5}()
> @ Main ./REPL[12]:3
> [2] top-level scope
> @ REPL[15]:1
> 
> julia> struct B{M, N} <: A{N} # constructor can be changed
> function B{M, N}() where {M, N}
> if !(N == M+2) throw("blah") end
> new{M,N}()
> end
> end
> 
> julia> B{3,5}()
> B{3, 5}()
> 
> julia> B{M}() where M = B{M, M+2}() # this UnionAll constructor helps constraint
> 
> julia> B{3}()
> B{3, 5}()
> 
> ```

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [November 13, 2023, 7:21pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/3 "2023-11-13T19:21:31Z")

</div>

But do checkout [GitHub - vtjnash/ComputedFieldTypes.jl: Build types in Julia where some fields have computed types](https://github.com/vtjnash/ComputedFieldTypes.jl)

---

<div class="post-metadata">

### Author: ![jecs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jecs/32/1781_2.png) [@jecs](https://discourse.julialang.org/u/jecs)
#### Post date: [November 13, 2023, 7:39pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/4 "2023-11-13T19:39:18Z")

</div>

Wow, that package does exactly what I want. I imagine that it essentially does what Benny suggested, but in a manner that is transparent to the user.

---

<div class="post-metadata">

### Author: ![jecs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jecs/32/1781_2.png) [@jecs](https://discourse.julialang.org/u/jecs)
#### Post date: [November 13, 2023, 7:42pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/5 "2023-11-13T19:42:30Z")

</div>

I appreciate the comprehensive response!

As a C++ programmer, it seems a bit…outlandish to suggest that `3+1` could ever be expected to yield a value other than `4`, but such is the way of Julia’s type system, I suppose.

Thanks!

---

<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: [November 13, 2023, 7:45pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/6 "2023-11-13T19:45:29Z")

</div>

> [@jecs](#):
>
> Wow, that package does exactly what I want.

You sure? I’ve never managed to make it work on type parameters in the header alone:

```julia
julia> @computed struct B{M} <: A{M+1} end
ERROR: MethodError: no method matching +(::TypeVar, ::Int64)
...

```

Aside: be aware that ComputedFieldTypes implicitly introduces type parameters, much like `B{M, N}` earlier. Constructors are omitted so it appears as if only the declared parameters `M` exist, but `B{M}` won’t be the concrete type, which can be computed with `fulltype(B{M})`. If you change any of the methods used to compute the fields’ types, not everything can adjust to `B{M}` referring to a different type. It can be convenient syntactic sugar, but I ended up preferring not to hide the extra parameters and constructors.

> [@jecs](#):
>
> As a C++ programmer, it seems a bit…outlandish to suggest that `3+1` could ever be expected to yield a value other than `4`

`+` can be assigned different functions in different modules without affecting each other, though a different name is probably more sane.

---

<div class="post-metadata">

### Author: ![jecs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jecs/32/1781_2.png) [@jecs](https://discourse.julialang.org/u/jecs)
#### Post date: [November 13, 2023, 7:47pm UTC](https://discourse.julialang.org/t/modifying-typevar-that-will-have-a-concrete-value/106149/7 "2023-11-13T19:47:17Z")

</div>

> You sure? I’ve never managed to make it work on type parameters in the header alone:

Oops, I should have tried it before commenting. 😅

> `+` can be assigned different functions in different modules without affecting each other, though a different name is probably more sane.

Ahh, I see! OK, that actually makes a lot of sense. Thanks again for demystifying this stuff.
