Reputation: 33
I am trying out the Julia language (coming from a Python background) and am interested in the most natural way to tackle an issue I would have solved using objects in Python.
Basically, I am trying to program a function that will evaluate some simple 1-d mathematical bases and then combine them to approximate a multidimensional function. In Python I would have written something like
basis_1d_values = scheme_1d.evaluate(points)
for each of my scheme_1d
objects. I would use a parent Scheme1d class, and then have subclasses for the various types of 1-d schemes (linear, Chebyshev polynomial, etc.) that would know how to run their separate "evaluate" functions.
What is the most natural way to do this in Julia? Obviously a long if statement like
if scheme_1d_type == "linear"
basis_1d_values = evaluate_linear(scheme_1d, points)
elif scheme_1d_type == "chebyshev"
basis_1d_values = evaluate_chebyshev(scheme_1d, points)
elif ...
...
end
will work but it is very clunky since I will need to use these branching if statements and separate functions every time the subclasses behave differently (and will have to keep track of every if statement when I update the code in some way). Any suggestions would be much appreciated.
Thank you!
Upvotes: 3
Views: 177
Reputation: 4510
You're talking about multiple dispatch and subtyping, which are very fundamental and peculiar to Julia and would be covered in any introduction tutorial. I'm not going to explain it all because they do a better job, but since you're coming from Python specifically , I can point out basic analogies.
Python can only dispatch (selecting a method) on 1 object so you make it its own type (class) that holds its own version of evaluate
, even write it before the dot during a function call, just to point out how special it is.
class Scheme1D:
pass
class Linear(Scheme1D):
def evaluate(self, points):
return "linear"
class Chebyshev(Scheme1D):
def evaluate(self, points):
return "chebyshev"
points = None
scheme_1d = Linear()
scheme_1d.evaluate(points)
# Python checks for type(scheme_1d) to find the correct evaluate
# and runs its bytecode (which was compiled upon class definition)
Julia dispatches on both scheme_1d
and points
(hence multiple dispatch), so evaluate
wouldn't belong to any type. Instead, it is 1 function with multiple methods, each method distinguished by its combined input types.
abstract type Scheme1D end
struct Linear <: Scheme1D
end
struct Chebyshev <: Scheme1D
end
# first method definition also creates the function
function evaluate(x::Linear, points)
return "linear"
end
# adds a method to the function
function evaluate(x::Chebyshev, points)
return "chebyshev"
end
points = nothing
scheme_1d = Linear()
evaluate(scheme_1d, points)
# Julia checks the types of scheme_1d and points, finds the
# most fitting method, compiles the method for those types
# if it is the first call, and runs the method
This should help you adjust to Julia, but you should really look up tutorials for the finer details. Just a couple more things that'll be helpful to keep in mind when you're learning:
points
was never specified a type so it is implicitly given the universal abstract type Any
), and Julia will make multiple specializations for every fitting concrete type.methodinstances
function of the MethodAnalysis
package is the current go-to way of seeing these.Upvotes: 5
Reputation: 6423
Not sure I understood all, but it wouldn't much different than in Python: you may use an abstract type Scheme_1d
and then create the specific linear, chebyshev, etc schemes as subtypes.
Then you would have a single evaluate_scheme(scheme,points)
function that dispatch based on the type of the scheme (refer to the documentation about "multiple dispatch").
Upvotes: 0