# Parametric type (new struct) whose parameter is a constant of a specific type?

**URL:** <https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049>\
**Category:** General Usage\
**Tags:** parametric-types\
**Created:** [June 22, 2024, 11:46am UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049 "2024-06-22T11:46:21Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Leo\_I](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leo_i/32/27262_2.png) [@Leo\_I](https://discourse.julialang.org/u/Leo_I)\
**Post date:** [June 22, 2024, 11:46am UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049/1 "2024-06-22T11:46:21Z")

</div>

I wish to create an efficient type for integers modulo `m`. Yes, I do realize there are several existing ones out there, but I wish to have my own, and perhaps squeeze a bit more performance out of it.

I’ve already achieved this in this GitHub [issue](https://github.com/scheinerman/Mods.jl/issues/31).  
But I wish to further improve on this. Observe the code:

```julia
abstract type AbstractModInt <: Number end;
struct Mod8{m} <:AbstractModInt where {m<:UInt8} # m=modulus is a concrete value; during runtime it is not checked that m is of type UInt8
    val ::UInt8 
    function Mod8{m}(val ::tw) where {m, tw<:UInt8}
        return new{m}(mod(val,m)) end end;

```

It allows creating `Mod8{UInt8(5)}`, but also `Mod8{Int(5)}, Mod8{Int}, ...`, which is not what I wanted. How can I have a constant `m::UInt8` as the type parameter, which is checked only at compile time, not at run time?

I’ve noticed there’s `Val{m}`, but am unsure how to use it.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 22, 2024, 12:01pm UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049/2 "2024-06-22T12:01:59Z")

</div>

Taking your question literally (_how to constrain the value of a type parameter to some type?_), the answer is you can’t, at least currently.

Your goal can be accomplished, though, by encoding `m` using a Zermelo ordinal-like construction (@Sukera). E.g., this is a recent piece of code of mine for representing natural numbers in the type domain, inspired by Zermelo ordinals:

```julia
module TypeDomainNaturalNumbers

module Internals
    export Internal
    struct Internal end
end

module TupleTail
    export tuple_tail
    function vararg_tail((@nospecialize ::Any), @nospecialize r...)
        r
    end
    function tuple_tail(@nospecialize t::Tuple{Any,Vararg})
        vararg_tail(t...)::Tuple
    end
end

export NonnegativeInteger, PositiveInteger, natural_successor, natural_predecessor, natural_tuple_length

abstract type AbstractNonnegativeInteger end

"""
    NonnegativeInteger

Nonnegative integers in the type domain.

The implementation is inspired by the Zermelo construction of the natural numbers.
"""
struct NonnegativeInteger{
    Predecessor<:Union{Nothing,AbstractNonnegativeInteger},
} <: AbstractNonnegativeInteger
    predecessor::Predecessor
    function NonnegativeInteger{P}(::Internal, p::P) where {P}
        new{P}(p)
    end
end

"""
    PositiveInteger

Positive integers in the type domain.
"""
const PositiveInteger = let t = NonnegativeInteger
    t{<:t}
end::Type{<:NonnegativeInteger}

"""
    natural_successor(::NonnegativeInteger)

Return the successor of a natural number.
"""
function natural_successor(o::NonnegativeInteger)
    NonnegativeInteger{typeof(o)}(Internal(), o)::PositiveInteger
end

"""
    natural_predecessor(::PositiveInteger)

Return the predecessor of a nonzero natural number.
"""
function natural_predecessor(o::PositiveInteger)
    o.predecessor::NonnegativeInteger
end

function (::Type{NonnegativeInteger})()
    NonnegativeInteger{Nothing}(Internal(), nothing)
end

function Base.zero(::Type{NonnegativeInteger})
    NonnegativeInteger()
end

function to_int(@nospecialize o::NonnegativeInteger)
    if o isa PositiveInteger
        let p = natural_predecessor(o), t = @inline to_int(p)
            t::Int + 1
        end
    else
        0
    end::Int
end

function Base.convert(::Type{Int}, o::NonnegativeInteger)
    to_int(o)
end

function from_val(::Val{N}) where {N}
    Vararg{Any,N}
    if N === 0
        NonnegativeInteger()
    else
        let v = Val{N - 1}(), p = @inline from_val(v)
            natural_successor(p::NonnegativeInteger)
        end::PositiveInteger
    end::NonnegativeInteger
end

function from_int(n::Int)
    Vararg{Any,n}
    if n === 0
        NonnegativeInteger()
    else
        from_val(Val{n}())
    end::NonnegativeInteger
end

function Base.convert(::Type{NonnegativeInteger}, n::Int)
    from_int(n)
end

"""
    natural_tuple_length(::Tuple)

Return a nonnegative integer which is the length of the given tuple.
"""
function natural_tuple_length(@nospecialize t::Tuple)
    if t === ()
        NonnegativeInteger()
    else
        let a = tuple_tail(t), b = @inline natural_tuple_length(a)
            natural_successor(b::NonnegativeInteger)
        end::PositiveInteger
    end::NonnegativeInteger
end

end

```

Then you could do something like this for your own type:

```julia
struct Mod8{M<:NonnegativeInteger}
    val::UInt8
end

```

Then you can convert `M` to `Int` or `UInt8` or whatever as needed. Technically you could also constrain `M` to be less than 256 by constraining it with a big `Union` of `NonnegativeInteger` subtypes, however I guess this would make Julia’s subtyping really slow.

---

<div class="post-metadata">

**Author:** ![Leo\_I](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leo_i/32/27262_2.png) [@Leo\_I](https://discourse.julialang.org/u/Leo_I)\
**Post date:** [June 22, 2024, 12:11pm UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049/3 "2024-06-22T12:11:59Z")

</div>

Uhm, I’m a bit lost in your code, I don’t understand what all `module`s have to do with my modular integers? Isn’t `module` used to isolate namespaces and create packages, precompile them, …

Could you post a MWE on how my type could be implemented, pls? Or is all of the above code necessary?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 22, 2024, 12:34pm UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049/4 "2024-06-22T12:34:33Z")

</div>

Your problem is the fact that in Julia it’s currently not possible to constrain non-`Type` type parameters. My proposal is to work around this by encoding the nonnegative integer value (`m`) as a type (`M`). I expect that you probably don’t want to bother with implementing this while you’re still a newbie, but perhaps you like this as food-for-thought.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [June 22, 2024, 9:06pm UTC](https://discourse.julialang.org/t/parametric-type-new-struct-whose-parameter-is-a-constant-of-a-specific-type/116049/5 "2024-06-22T21:06:15Z")

</div>

You can always do something like the following:

```julia
struct Mod8{m}
    val::UInt8 
    function Mod8(m::UInt8, val::UInt8)
        new{m}(val)
    end
end

```

Now you can only make a `Mod8{m}` with `m::UInt8` because this is what is returned by the inner constructor.

Then of course you can add more constructors for convenience, such as:

```julia
function Mod8(m::Integer, val::Integer)
    Mod8(convert(UInt8, m), convert(UInt8, val))
end

```
