1

I would like to do something like this:

Base.@kwdef mutable struct Setup
    # physics
    lx   = 20.0
    dc   = 1.0
    n    = 4
    # inital condition
    ic(x) = exp(-(x-lx/4)^2)
    # numerics
    nx   = 200
    nvis = 50
    # derived numerics
    dx   = lx/nx
    dt   = dx^2/dc/10
    nt   = nx^2 ÷ 5
    # arrays
    xc   = LinRange(dx/2,lx-dx/2,nx)
    C0 = ic.(xc)
    C = copy(C)
    q = zeros(nx-1)
    # collections for easy use
    dgl_params=[dc,n]
end

The problem here is that it says ic was undefined. Makes sense, because ic is not in the global scope. Then I tried writing an outside constructor instead (I am not writing an inside constructor as that would overwrite the default constructor).

Base.@kwdef mutable struct Setup
    # physics
    lx   = 20.0
    dc   = 1.0
    n    = 4
    # inital condition
    ic(x) = exp(-(x-lx/4)^2)
    # numerics
    nx   = 200
    nvis = 50
    # derived numerics
    dx   = lx/nx
    dt   = dx^2/dc/10
    nt   = nx^2 ÷ 5
    # arrays
    xc   = LinRange(dx/2,lx-dx/2,nx)
    # C0 = ic.(xc)
    C0
    C = copy(C)
    q = zeros(nx-1)
    # collections for easy use
    dgl_params=[dc,n]
end

function Setup()
    Setup(Setup.ic(Setup.xc))
end
Setup()

But now it says DataType has no field ic which of course makes sense, I want the ic of the object itself. However there appears to be no selfor this keyword in julia. Strangely enough the above seems to work fine with dx or dt which are also depending on other variables

3 Answers3

2

Actually, it is not in the design to have what in Java or C++ you would call "member functions". Part of this is Julia's will to benefit from the multiple dispatch programming paradigm. In Julia, mutables are pointers, so you pass them directly to a function, e.g.

function ic(setup::Setup, x)
    return exp(-(x-setup.lx/4)^2)
end

That said, there is still a way to have more Java-esque classes, though not super recommended. Check this thread and, particularly, the answered marked as solution, given by one of Julia's authors themself.

JustLearning
  • 1,435
  • 1
  • 1
  • 9
2
  1. Normally the design is to have multiple dispatch and functions outside of the object
  2. When creating structs always provide the datatype of elements
  3. For this large structs usually you will find out that using Parameters package will be more convenient when later debugging
  4. The easiest way to circumvent the limitation is to have a lambda function in a field such as (this is however not the recommended Julia style):
@with_kw mutable struct Setup
       lx::Float64 = 20.0
       ic::Function = x -> lx * x
end

This can be now used as:

julia> s = Setup(lx=30)
Setup
  lx: Float64 30.0
  ic: #10 (function of type var"#10#14"{Int64})


julia> s.ic(10)
300
Przemyslaw Szufel
  • 40,002
  • 3
  • 32
  • 62
1

Okay, I found the solution. This does not work, because there are no methods in julia:

Base.@kwdef mutable struct S
    n = 5
    m
    f(x) = x + 100
    A = f.(randn(n,m))
end

s = S(m=5) # ERROR: UndefVarError: f not defined
s.A
s.f(5)

But this does work, because here f is a variable and not a function

Base.@kwdef mutable struct S
    n = 5
    m
    f= x-> x + 100
    A = f.(randn(n,m))
end

s = S(m=5)
s.A
s.f(5)