Object oriented coding#
Why?#
Suppose you have a kink and you’d like to calculate it’s energy. To caculate this, you need to have the kink field, the grid, maybe some parameters and knowledge of the boundary conditions. You could write a calculate_energy
function. Because it needs all these things, you end up passing them all to the function. So to use it you need to write code that looks something like
calculate_energy(my_kink, grid, parameters, boundary_conditions)
This is ok, but can get out of hand quickly.
Another option is to represent your kink as an object (as a class in c++, a struct in Julia). Think of this as a template of your field, which bundles all its vital information together. So you might make a class which represents a kink with this structure
class Kink:
field
grid
parameters
boundary_conditions
You would then make your kink my_kink = Kink(…)
. Here my_kink
is an object of class (or struct) type Kink. When you pass it to the energy function, you only need to write…
calculate_energy(my_kink)
…since my_kink contains everything you need to know. There are more advantages than just making your code looks nicer. Classes and objects mean your field is closely tied together with the grid it’s on etc. So it should be harder to make mistakes.
You can also define methods. These are functions which are special for your classes. Then you can do things like: energy = my_kink.calculate_energy()
. Nice!
Examples#
Let’s make the aforementioned kink. To be more specific, we’ll make a class with:
an array representing the field
a float representing the lattice_spacing
an integer representing the number of lattice points,
a list of floats representing parameters
a string representing the bounadry conditions This isn’t neccisarly a perfect structure; but it’s good to try out making a class!
Here we go:
mutable struct Kink
field::Array{Float64}
ls::Float64
lp::Int64
pars::Vector{Float64}
boundary_conditions::String
end
Now how do we make a Kink
? First, you need to make an constructor. This varies a bit by language. One important point is that you make some values needed for constructor and while some can be optional; and go to a default value. In this example we’ll require the user to give the lattice spacing and lattice points but not the field, which will default to zeros. We’ll also give pars the default value of an array with one zero and the boundary_conditions equal to “Dirichlet”:
Kink(lp::Int64, ls::Float64; pars = [0], boundary_conditions=“Dirichlet" ) = Kink(zeros(lp), ls, lp, pars, boundary_conditions)
???
Then you can make my_kink
, on a grid of 100 points with lattice spacing 0.2 as follows: (The other elements of the class will take their default values)
my_kink = Kink(100, 0.2)
???
Now we can do things like print the field values, or change the parameters as follows:
print(my_kink.field)
my_kink.pars[0] = [2.0]
???
It might be a good idea to make a Grid class and a Parameters class. Then your Kink class will contain the field, a Grid and a Parameters.