julia

How do we do classes in Julia?


I have a problem with writing classes in Julia. I have looked at the documentation and I haven't seen any docs on classes.

In Python, classes are, for example,

class Dog:
   # ----blah blah---

How is this possible in Julia?


Solution

  • Julia does not have classes. Instead we define new types and then define methods on those types. Methods are not "owned" by the types they operate on. Instead, a method can be said to belong to a generic function of the same name as the method. For instance, there are many versions ("methods") of the length function; together they form the generic function length.

    Here's an extended example of the Julian approach to programming with types and methods. New types are declared using the struct keyword:

    struct Person
        name::String
        age::Int64
    end
    

    Now we can define methods on the Person type:

    name(p::Person) = p.name
    age(p::Person) = p.age
    
    bio(p::Person) = println("My name is ", name(p)," and I am ", age(p), " years old.")
    

    Methods can be defined for different combinations of argument types. To illustrate this, let's first define some new types:

    abstract type Pet end
    
    struct Cat <: Pet
        name::String
        color::String
    end
    
    name(c::Cat) = c.name
    color(c::Cat) = c.color
    species(::Cat) = "cat"
    
    struct Dog <: Pet
        name::String
        color::String
    end
    
    name(d::Dog) = d.name
    color(d::Dog) = d.color
    species(::Dog) = "dog"
    
    bio(p::Pet) = println("I have a ", color(p), " ", species(p), " named ", name(p), ".")
    
    struct Plant
        type::String
    end
    
    type(p::Plant) = p.type
    bio(p::Plant) = println("I have a ", type(p), " house plant.")
    

    At this point we can see that we've defined three different one-argument methods for bio:

    julia> methods(bio)
      3 methods for generic function "bio":
    [1] bio(p::Plant) in Main at REPL[17]:1
    [2] bio(p::Person) in Main at REPL[4]:1
    [3] bio(p::Pet) in Main at REPL[14]:1
    

    Note the comment in the output of methods(bio): "3 methods for generic function 'bio'". We see that bio is a generic function that currently has 3 methods defined for different function signatures. Now let's add a two-argument method for bio:

    function bio(person::Person, possession)
        bio(person)
        bio(possession)
    end
    

    Notice that this function is generic in the possession argument, since the internal call to bio(possession) will work whether the possession is a plant, cat, or dog! So we now have four total methods for bio:

    julia> methods(bio)
      4 methods for generic function "bio":
    [1] bio(p::Plant) in Main at REPL[17]:1
    [2] bio(p::Person) in Main at REPL[4]:1
    [3] bio(p::Pet) in Main at REPL[14]:1
    [4] bio(person::Person, possession) in Main at REPL[18]:1
    

    Now let's create a few instances of our types:

    alice = Person("Alice", 37)
    cat = Cat("Socks", "black")
    dog = Dog("Roger", "brown")
    plant = Plant("Boston Fern")
    

    So finally we can test our bio methods:

    julia> bio(alice, cat)
    My name is Alice and I am 37 years old.
    I have a black cat named Socks.
    
    julia> bio(alice, dog)
    My name is Alice and I am 37 years old.
    I have a brown dog named Roger.
    
    julia> bio(alice, plant)
    My name is Alice and I am 37 years old.
    I have a Boston Fern house plant.
    

    Side note: Modules are used primarily for namespace management. A single module can contain the definitions for multiple types and multiple methods.