# Parameterizing type by integer value using "where"

**URL:** <https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821>\
**Category:** General Usage\
**Created:** [October 15, 2021, 12:04pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821 "2021-10-15T12:04:40Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![John\_Gibson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/john_gibson/32/5321_2.png) [@John\_Gibson](https://discourse.julialang.org/u/John_Gibson)\
**Post date:** [October 15, 2021, 12:04pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/1 "2021-10-15T12:04:40Z")

</div>

This simple GaloisField type is parameterized by the modulus `p` and the integer type `T`. It works fine, but note that the test on the type of `p` buried within an inner constructor.

```julia
using Primes

# Type definition: GaloisField{p,T}, where p is prime modulus, T is integer type
struct GaloisField{p,T} <: Number where {p, T<:Integer}
    rep::T # representative integer

    # inner constructor
    function GaloisField{p,T}(x::Integer) where {p, T<:Integer}
        if !(typeof(p) <: Integer) || !isprime(p)
            throw(ArgumentError("p must be a prime integer"))
        end
        return new(mod(x, p))
    end
end
GaloisField{p}(x::T) where {p,T<:Integer} = GaloisField{p,T}(x)

```

It would seem better to require that `p` be an integer in the type signature, like this

```julia
using Primes

# Type definition: GaloisField{p,T}, where p is prime modulus, T is integer type
struct GaloisField{p,T} <: Number where {p::Integer, T<:Integer}
    rep::T # representative integer

    # inner constructor
    function GaloisField{p,T}(x::Integer) where {p::Integer, T<:Integer}
        if !isprime(p)
            throw(ArgumentError("p must be a prime"))
        end
        return new(mod(x, p))
    end
end
GaloisField{p}(x::T) where {p::Integer,T<:Integer} = GaloisField{p,T}(x)

```

but that gives the error

```julia
syntax: invalid variable expression in "where" around In[2]:4

Stacktrace:
 [1] top-level scope
   @ In[2]:4
 [2] eval
   @ ./boot.jl:360 [inlined]
 [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1094

```

Wouldn’t this be better? Why doesn’t it work?

And what’s with the syntax `const T2 = Array{Array{T, 1}, 1} where T` (from the UnionAll section of the Types in Julia Docs)? Am I supposed to read that as `...where T<:Any`? To me an unadorned `where T` is like an unfinished sentence.

The GaloisField code is an update of an example from a 2016ish talk by Andreas Noack.

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [October 15, 2021, 12:15pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/2 "2021-10-15T12:15:14Z")

</div>

I think you want to write `where {p<:Integer, T<:Integer}` since `Integer` is an abstract type.

> And what’s with the syntax `const T2 = Array{Array{T, 1}, 1} where T` (from the UnionAll section of the Types in Julia Docs)? Am I supposed to read that as `...where T<:Any` ? To me an unadorned `where T` is like an unfinished sentence.

I usually read it as “where `T` is some type” which seems to be the same as being a subtype of `Any`, but I don’t really know so maybe there could be something more intricate going on.

---

<div class="post-metadata">

**Author:** ![Bernard\_GODARD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bernard_godard/32/4155_2.png) [@Bernard\_GODARD](https://discourse.julialang.org/u/Bernard_GODARD)\
**Post date:** [October 15, 2021, 12:28pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/3 "2021-10-15T12:28:57Z")

</div>

You cannot constrain the type of non-type parameter with where. Only type parameters can be constrained with where.

T is a type and the constraint T\<:Integer signifies T must be a subtype of Integer  
while p is a value of type Integer but this kind of constraint (type of value is ) cannot be enforced by where.

See [https://github.com/JuliaLang/julia/issues/9580](https://github.com/JuliaLang/julia/issues/9580)

---

<div class="post-metadata">

**Author:** ![John\_Gibson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/john_gibson/32/5321_2.png) [@John\_Gibson](https://discourse.julialang.org/u/John_Gibson)\
**Post date:** [October 15, 2021, 12:33pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/4 "2021-10-15T12:33:41Z")

</div>

Sorry, I should have clarified that the type is parameterized by the _integer value_ of p. E.g.

```julia
julia> typeof(GaloisField{3,Int64}(1))

GaloisField{3, Int64}

```

This reflects the mathematics: the GaloisField with modulus p is a number system with p elements. Arithmetic is defined between elements of the same GaloisField, but, for example, you can’t add an element of a GaloisField with modulus 3 to an element of a GaloisField with modulus 5. So the type is parameterized by the value of the integer, as well as the integer type.

---

<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:** [October 15, 2021, 12:44pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/5 "2021-10-15T12:44:40Z")

</div>

the integer `3` you see is not \<:Ineteger:

```julia
julia> Array{Any, 3} <: Array{<:Any, <:Any}
true

julia> Array{Any, 3} <: Array{<:Any, <:Integer}
false

julia> Array{Any, Int64} <: Array{<:Any, <:Integer}
true

```

`<:Integer` means Int64, Int32 etc…

---

<div class="post-metadata">

**Author:** ![John\_Gibson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/john_gibson/32/5321_2.png) [@John\_Gibson](https://discourse.julialang.org/u/John_Gibson)\
**Post date:** [October 15, 2021, 12:52pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/6 "2021-10-15T12:52:38Z")

</div>

Yes, that’s why I want to specify `where{p::Integer,T<:Integer}` and not `where{p<:Integer,T<:Integer}`.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 15, 2021, 1:08pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/7 "2021-10-15T13:08:36Z")

</div>

Letting go of some explicit `Integer` constraints, internalizing validations:

```julia

julia> 
struct GaloisField{p,T} <: Number
   rep::T # representative integer
   # inner constructor
   function GaloisField{p,T}(x::Integer) where {p,T}
     if !isprime(p)
       throw(ArgumentError("p must be a prime"))
     elseif !(T <: Integer)
       throw(ArgumentError("T must be <:Integer"))
     end
     return new{p,T}(mod(T(x), p))
   end
 end

julia> GaloisField{11,Int32}(8)
GaloisField{11, Int32}(8)

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 15, 2021, 1:36pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/8 "2021-10-15T13:36:34Z")

</div>

or along the same lines, cleaner imo:

```julia
# this inner constructor is not called directly
struct GaloisField{p,T} <: Number
  rep::T # representative integer
  # inner constructor
  function GaloisField{p,T}(x::Integer) where {p,T}
    return new{p,T}(mod(T(x), T(p)))
  end
end

# this becomes the interface
function GaloisField(p::T, x::T) where {T<:Integer}
  if !isprime(p)
    throw(ArgumentError("p must be a prime"))
  end
  return GaloisField{p, T}(x)
end
```

---

<div class="post-metadata">

**Author:** ![John\_Gibson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/john_gibson/32/5321_2.png) [@John\_Gibson](https://discourse.julialang.org/u/John_Gibson)\
**Post date:** [October 15, 2021, 1:36pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/9 "2021-10-15T13:36:58Z")

</div>

Yes, you can do this, but relying on internal, user-defined type-checking seems harder to read & understand and more error-prone than declaring type constraints up front and letting the compiler enforce them.

---

<div class="post-metadata">

**Author:** ![John\_Gibson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/john_gibson/32/5321_2.png) [@John\_Gibson](https://discourse.julialang.org/u/John_Gibson)\
**Post date:** [October 15, 2021, 1:40pm UTC](https://discourse.julialang.org/t/parameterizing-type-by-integer-value-using-where/69821/10 "2021-10-15T13:40:08Z")

</div>

Ah, I like your “cleaner imo” solution, having the user interface be `function GaloisField(p::T, x::T) where {T<:Integer}`.
