"where" syntax

I’m trying to update the following code (taken from an Andreas Noack talk) from to julia-0.5 to julia-0.6. The GF{P,T} type represents a finite Galois field, essentially the integers modulo P where P is prime.

# Scalar finite fields. P is the modulus, T is the integer type (Int16, Int32, ...)
immutable GF{P,T<:Integer} <: Number
    data::T
    function GF(x::Integer)
        return new(mod(x, P))
    end
end

julia-0.6 gives the warning

WARNING: deprecated syntax "inner constructor GF(...) around REPL[6]:5".
Use "GF{P,T}(...) where {P,T}" instead.

What is the correct revision of the immutable GF type declaration? I’ve read documentation and have tried a number of things, but Im afraid I can’t figure it out.

julia> struct GF{P,T<:Integer} <: Number
           data::T
           function GF{P,T}(x::Integer) where {P, T}
               return new(mod(x, P))
           end
       end
1 Like

As suggested by the warning, you should do:

struct GF{P,T<:Integer} <: Number
    data::T
    GF{P,T}(x::T) where {P,T<:Integer} = new(mod(x, P))
end

You can also add an outer constructor

GF{P}(x::T) where {P,T<:Integer} = GF{P,T}(x)

to avoid needing to call GF{6,Int}(7), and instead only specify the modulus: GF{6}(7)

1 Like

@cstjean & @jebej, thank you!

Canyou explain the difference between GF{P,T}(x::Integer) where {P, T} and GF{P,T}(x::T) where {P,T<:Integer} in your answers? Both work, but I don’t understand what the first accomplishes.

@jebej your outer constructer prevents an infinite loop that otherwise occurs during instantiation of GF{9}(5), which was the next item on my agenda. Thanks for that, too.

Note that with the new syntax, you can now also do

julia> struct GF{P,T<:Integer} <: Number
           data::T
           function GF{P}(x::Integer) where P
               data = mod(x, P)
               new{P, typeof(data)}(data)
           end
       end

julia> GF{4}(15)
GF{4,Int64}(3)

In that case I believe the two methods will be identical. I wrote it that way to be explicit that the parameter T will be the type of x.

They won’t necessarily do the same thing if typeof(x) is not the same as T. The syntax GF{P,T}(x::Integer) allows you to specify the type of the data field of GF directly, independent of the type of x (but still constrains x to be an Integer, of course). So it allows GF{4,Int64}(Int32(4)), for example.

I don’t understand the purpose of where {P,T} below. What information is that providing to the compiler?

I can better understand the point of where in @jebej’s GF{P,T}(x::T) where {P,T<:Integer} = new(mod(x, P)). It’s specifying that this function aapplies only when T is a subtype of Integer. But in the other case, it looks like the compiler is requiring me to provide a constraint that is empty.

I clearly don’t understand the where keyword. It is brought up incidentally in the Types and Methods pages of https://docs.julialang.org, but I don’t find an explanation anywhere of its purpose with simple explanatory examples of its main uses. Where should I look for that? An issue on Julia github?

1 Like

Stefan has a really excellent answer justifying the new where syntax on stackoverflow.

3 Likes

The stackoverflow discussion lalso ead me to this where syntax thread on Discourse from July --which I would have found had I searched “where syntax” Discourse instead of Google in the first place. Thanks everyone for the help.