avatarEmma Boudreau

Summary

The web content provides a tutorial on creating custom exceptions in Julia, detailing the process of defining an exception type, handling errors, and integrating with Julia's Base exception system.

Abstract

The article "How To Create Exceptions In Julia" delves into the intricacies of exception handling within the Julia programming language. The author begins by discussing the importance of proper type hierarchy when creating custom exceptions, emphasizing the need for common fields such as msg and code for seamless integration with Julia's Base methods. The tutorial guides readers through defining a new exception type, MyException, as a subtype of the abstract Exception type from Julia's Base library. It also covers the implementation of the showerror function to customize error message display and demonstrates error handling with a teste function that raises MyException when an error occurs during type conversion. The article concludes by highlighting Julia's extensibility and the ease of integrating custom types with Base functionality, contrasting it with other languages like Python, where such integration can be more cumbersome.

Opinions

  • The author believes that Julia's design, which emphasizes extensibility and multiple dispatch, provides a superior programming experience compared to other languages.
  • They suggest that directly importing types might aid precompilation and method dispatch, although this concept has not been explicitly tested.
  • The author expresses that Julia's approach to exception handling and type system allows for more fluid and less verbose code compared to languages like Python.
  • They advocate for the use of Julia, particularly for developers interested in creating efficient and clean code, and recommend it for those considering exploring new programming languages.

How To Create Exceptions In Julia

How to create and raise exceptions in Julia

Lately, I have been struggling to find topics to discuss on my blog because I am currently invested in developing my web-framework and things right now. However, while working on Toolips, I did implement some exceptions via Base and I realized that this would make a really cool topic from an article. Today we are going to be extending Julia’s Base by designing our own exception and binding it to a few simple methods.

Abstract Type Exception

In order to properly inherit methods, in most cases, we need to pay attention to its position on the type hierarchy. There are common consistencies amongst exceptions in general such as a common field msg and code that will be automatically used to bind your exception to more Base methods. Although the example will not be including this, it might be a great idea, seeing as there is likely a-lot more dispatch to be inherited correctly. As such, we start this process by making our new Exception type, which needs to be a sub-type of Exception — an abstract type from Base. I also like to directly import any type I use abstractly, I just imagine this could help with precompilation to some degree; directly importing the types. I have not tested this concept, it just seems realistic that Julia typing might have an easier time adding methods to a type that is directly imported. Alongside this import, we are also going to want to import Base.showerror , as this is how we will be designing how we want to raise our exceptions.

import Base: showerror, Exception
mutable struct MyException <: Exception
    type::Type
    except::Exception
end

In this basic example, we are meant to catch when an error happens, and then record both the type and the exception that caused this error.

base.showerror

The next step in this process is binding the showerror method from Base, which of course gets called whenever stdout shows an error.

showerror(io::IO, e::MyException) = print(io, "MyException !: by $e")

With this little bit of code, we are already off to the races. Finally, we will build a little example that will catch our error if we cannot add it to an Int64. this will produce a MethodError for no method matching +(::String ::Int64) if we passed a String, for example, but happily will take an Integer, which is why it is probably a great idea to keep your dispatch annotations not set to Any, but anyway …

julia> function teste(x::Any)
           try
               x += 1
           catch e
               throw(MyException(typeof(e), e))
           end
           return x
       end

I decided to use +=, which is slightly different, but also gives a return — which is nice. Testing an integer works fine:

julia> teste(5)
6

However, when the input is a string:

julia> teste("hello")
ERROR: MyException !: by MyException(MethodError, MethodError(+, ("hello", 1), 0x0000000000007a6b))
Stacktrace:
 [1] teste(x::String)
   @ Main ./REPL[4]:5
 [2] top-level scope
   @ REPL[6]:1

Whoops, I accidentally provided myexception instead of raising the method error. We were actually looking for the fieldname except on e:

showerror(io::IO, e::MyException) = print(io, "MyException !: by $(e.except)")

Implementing this,

julia> showerror(io::IO, e::MyException) = print(io, "MyException !: by $(e.except)")
showerror (generic function with 56 methods)
julia> teste("hello")
ERROR: MyException !: by MethodError(+, ("hello", 1), 0x0000000000007a6c)
Stacktrace:
 [1] teste(x::String)
   @ Main ./REPL[4]:5
 [2] top-level scope
   @ REPL[8]:1
caused by: MethodError: no method matching +(::String, ::Int64)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at /opt/julia-1.6.3/julia-1.6.3/share/julia/base/operators.jl:655
  +(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at /opt/julia-1.6.3/julia-1.6.3/share/julia/base/int.jl:87
  +(::Base.TwicePrecision, ::Number) at /opt/julia-1.6.3/julia-1.6.3/share/julia/base/twiceprecision.jl:279
  ...
Stacktrace:
 [1] teste(x::String)
   @ Main ./REPL[4]:3
 [2] top-level scope
   @ REPL[8]:1

In Julia, Base extensibility, and being able to implement your own tools in an instant, culminates into a really awesome programming experience. The difference in most languages is that they are not built from the beginning, at the core of their paradigm, to work in the same way Julia does. With Julia, multiple methods per type and adding methods together from different places was a focus. Even in languages that might let you do similar things with their built-ins, it is often much more cobbled together — and extending it is not at all as fluid as it is seen here.

A great example of this would be Python. In Python, in order to add indexing we have to add some weird default PyObject function into a class, in Julia we just use multiple dispatch and bind the getindex() method to our type. Not only is it easier, but it also makes for a lot less code to glue things like that together. Nowhere else could you create a lot of the things in such a short amount of time. Thank you for reading, and if you are considering looking into Julia, I cannot recommend it enough!

Programming
Julia
Software Development
Coding
Technology
Recommended from ReadMedium