Julia Has Unparalleled Extensibility.
No other language is like this; extending modules with Julia.

What is the most important contributing factor to the speed at which software is developed? One argument hat I would present for the answer to that question is extensibility. Extensibility is important for software because it allows for the re-use of old code in order to make new code. A great example can be seen at the root of the creation of inheritance; C++. C++ was one of the first languages to implement the sub-class and abstraction system that is used for inheritance in so many programming languages today, taking the idea originally from a language called Simula and taking it to new extremes. These new sub-classes allowed types to be described as many categorical definitions, all with appropriate methods and abilities.
While C++ made a significant impact with this original approach to inheritance and abstraction, a recently developed programming language has taken extensibility to an entirely new level. Meet Julia; a JIT-compiled, dynamically-typed language released around a decade ago. The language features multiple dispatch as a paradigm, and boasts some pretty amazing performance metrics. While these are things that programmers are used to hearing about Julia, one thing that might not be quite as synonymous with the language is the absolutely unparalleled extensibility to methods, types, and more that this language has. This is especially the case for a more traditional function + struct almost functional programming language. Julia is an incredibly easy and fun to extend language, and today I wanted to demonstrate not only how to extend Julia, but also why I think that there are few languages who mount a rivalry to this sort of code.
Methods
The first and most obvious way to extend Julia is by method. Methods and multiple dispatch are the bread and butter of the Julia language, and applying these programming concepts to extensibility makes for some pretty awesome results. Methods in Julia are defined by Functions that have typed arguments. A Method is actually a field of a Function type. Where things get awesome is once we realize that we can add to these methods and change them to create new combinations of types under the same function. This is called multiple dispatch, and this is the quintessential feature of Julia’s paradigm. Here is an example where I make a function to make a Python-style addition operator which does concatenation on Strings and addition on Integers:
Py+(x::String, y::String) = x * y
Py+(x::Int64, y::Int64) = x + yMultiple dispatch is awesome, but this paradigm is also used as a platform at which to extend Julia code. Julia code is typically stored in Modules. From these modules we can directly import different method names in order to add new functionality to them with dispatch. Briefly, let us try the same arguments, (::String, ::String) through the Base operator, +.
"hi" + "hello"
ERROR: MethodError: no method matching +(::String, ::String)
Closest candidates are:
......Whenever we try this, we get a method error. This is fortunate, because it means that the method +(::String, ::String) is not currently bound to anything, and we could easily make this operator do what it does in Python by just linking it to *. In order to extend a function with new methods like this, we will need to directly import whatever method we want to work with. In this example, we will be importing Base.+.
import Base: +
+(x::String, y::String) = x * yNow our Pythonic string concatenation has been brought into fruition, and all with just one in-paradigm line of code!
"hi" + "hello"
"hihello"There are actually so many different things in Julia like this which are cleverly applied through multiple dispatch. This is one thing I really think is awesome about Julia, multiple dispatch becomes the current at which some really awesome ideas are implemented that make programming a lot easier.
Supertypes
Another very important aspect to the extensions inside of Julia is the super-type hierarchy. The super-type hierarchy allows us to extend types, rather than methods, which allows us to inherit the methods of the types which are defined as a super-type for a given type. This also fits really well into the paradigm of Julia, as these methods which are defined for a given type are of course using multiple dispatch, and we can dispatch further and further down the type hierarchy in order to alter specific function calls for specific sub-types. A great example of this is how exceptions are written in Julia. The following code will be pulled from my overview on exceptions in Julia:
First, we can create a sub-type of Base.Exception. This is done using the sub-type operator, <:, which is used both to set sub-types as well as to determine whether or not a given type is a sub-type.
import Base: showerror, Exceptionmutable struct MyException <: Exception
type::Type
except::Exception
endThis new Exception inherits the methods from Base.Exception, so any method that was made for all other Exceptions is now a method for our new type! We can also build more specific dispatches, in this instance, we will want to bind the showerror method from Base.
showerror(io::IO, e::MyException) = print(io, "MyException !: by $e")While these two techniques might seem reasonably simple, they create an infinite number of possibilities when it comes to extensibility. This is part of the reason Julia packages are often modular and separated; the language makes it really easy to make modular code! Compared to other languages, Julia really steps up to the plate and creates some awesomeness on this front, and this is a feature that I really like about the language.
I hope this little overview on Julia being incredibly extendable was cool to read. Thank you for reading it, it means the world to me!
