Class Constructor

I’m trying to generate a struct, and one of the of the elements of the struct depends on a parameter of the class. I’m not really sure how to do it tho

Example of what I’m doing

struct SpectralDiscretization1D

    Space
    kind #:Fourier, :Cheb1, :Cheb2, :Leg
    N  #Number of points
    A #Matrix needed for change of coordinates, can it be FFT, DCT, LegMatrix, etc.
    A⁻¹ #Inverse of A 
    
    if kind == :Cheb1
        DCT = FFTW.plan_r2r(ones(N) ,FFTW.REDFT00, 1, flags = FFTW.MEASURE)
        SpectralDiscretization1D(Space, kind, N) = new(Space, kind, N, DCT, DCT)    
        A = FFTW.plan_r2r(ones(N) ,FFTW.REDFT00, 1, flags = FFTW.MEASURE)
        A⁻¹ = A

    elseif kind == :Cheb2
        DCT = FFTW.plan_r2r(ones(N) ,FFTW.REDFT10, 1, flags = FFTW.MEASURE)
        SpectralDiscretization1D(Space, kind, N) = new(Space, kind, N, DCT, DCT)


    end


end

But I get the error

ERROR: UndefVarError: kind not defined

What is the correct way of doing this?

You should be able to do this with inner constructor. There is an example in docs
https://docs.julialang.org/en/v1/manual/constructors/
How to do that.

2 Likes

I want to be able to give more than only 2 options (and hopefully not everything in one line) and I’m not sure how to extend the example of the documentation

It doesn’t have to all be on one line. See below

julia> struct M
           x::Float64
           
           function M(x)
               if x > 1.0
                   x = 1.0
               elseif x < 0.0
                   x = 0.0
               end
               new(x)
           end
       end

julia> M(20.0)
M(1.0)
1 Like

Sorry for nit-picking, but getting the terminology straight makes it a lot easier to find an actual solution to your problem.

  • parameters (of a type/struct): see here Types · The Julia Language
    I think what you are referring to in the original question is the fields of the struct (like kind, N, etc.) This difference is important, because perhaps what you really want to use are parameters
  • class: doesn’t exist, but also doesn’t matter – structs also have constructors and as @Tomas_Pevny said, an inner constructor gives you the ability to compute the values of some fields based on the inputs to the constructor

Here is how that might work in your case:

struct SpectralDiscretization1D
    Space
    kind
    N
    A
    A⁻¹
    
    # Inner constructor – works like any other function except that it has to be in the struct block and should return some `new(...)` object
    function SpectralDiscretization1D(Space, kind, N)
        # Here goes your logic that constructs the fields based on, e.g. kind and N (or anything else
        if kind == :Cheb1
            DCT = FFTW.plan_r2r(ones(N) ,FFTW.REDFT00, 1, flags = FFTW.MEASURE)
            A = FFTW.plan_r2r(ones(N) ,FFTW.REDFT00, 1, flags = FFTW.MEASURE)
            A⁻¹ = A
            return new(Space, kind, N, A, A⁻¹)
        elseif kind == :Cheb2
            DCT = FFTW.plan_r2r(ones(N) ,FFTW.REDFT10, 1, flags = FFTW.MEASURE)
            return = new(Space, kind, N, DCT, DCT)
        end
    end
end

Note that defining your own inner constructors will “overwrite” the default constructor. This might be what you want, but you can also just make the constructors “outer constructors” instead.

Just a tip: it might be worth fixing the type of the fields of your struct to get more optimized compiled versions of your code.

3 Likes