Teaching with Julia vs. teaching with MATLAB
In fall 2020, I was set to teach our first-semester computational math course using my co-authored book with its couple of hundred or so MATLAB codes. Then I was approached by an honors student about doing an add-on honors section. I’ve never quite known what to do with these. How to make a more enriching experience without adding a ton of extra effort for me and for the students?
However, the timing was interesting. I had been working on a Julia version of the book for a while, and needed some field testing. So I had five volunteer guinea pigs, among the best and most motivated students. If they couldn’t make it work, then probably few students could.
In short, that field test was a bigger success than I had hoped. The honors students needed surprisingly little coaching through the installation and use of Julia, a package for the book software, and Jupyter. There were no significant bugs.
What I had not anticipated was how interesting it would be for me to be teaching groups of students the same material simultaneously in both computing languages. It’s not an experiment, given the self-selection of the students; in particular, the MATLAB group included both strong and much weaker students. But some differences about the pedagogical use cases were highlighted.
For me, almost nothing important here comes down to big features like multiple dispatch and threading in Julia, or mature applications packages in MATLAB. Those things are beyond the scope of what I can try to convey, which is decent programming practice in the service of learning concepts. Instead, the differences I encounter when teaching have more to do with what you might call quality of life issues when getting to know a language and its ecosystem.
In MATLAB’s favor
Packaging. MathWorks has been selling MATLAB for decades, and the installation process is about as smooth as a license-locked program could be. An army of service agents is standing by to help, although I don’t always hear great things about that experience. There is even some package management built in.
(Not for the first time, I found it astonishing and discouraging that despite being given a link to the book’s files as a one-click installation, many students persisted in typing in the functions—thereby introducing mistakes—or even copying from the PDF to paste into the editor.)
Julia’s package manager is superb, possibly unparalleled, and it mostly gets out of the way. Yet it exposes issues that simply don’t exist for baby MATLAB users. JuliaPro is one answer, but it still uses Atom/Juno and is, at this moment, behind on the Julia version. For me personally, life is too precious to spend it setting up a JupyterHub. There are some cloud solutions, although then payment becomes an issue.
Documentation. The documentation in MATLAB is second to none. It’s all mirrored on the web as well as integrated within the IDE and the command line. By contrast, documentation in Julia remains highly variable. Even when there are great and helpful websites, the documentation of individual functions (outside of the base) is often spotty and is sometimes aimed at a sophisticated user. Even when there is good documentation, it can be difficult to find what you want for a function with many methods. Writing documentation is hard and pretty thankless, so it’s no surprise that a top-down organization with a lot of money and a big headstart enjoys an advantage. As long as I’m taking potshots at Julia here, though, error reporting is also…not fantastic.
Help. There is an avalanche of texts, videos, and interactive tutorials for learning just about anything for MATLAB, including a nontrivial intersection of free and high-quality. MATLAB has maintained backward compatibility so well that almost all of this help remains accurate, although sometimes obsolete. There is the downside that your students might find a little too much help, of course.
By contrast, Julia is still young and such a moving target that googling for help can be an adventure. While there are helpful and responsive communities on Discourse and Reddit, for example, students are mostly too shy?/guilty?/procrastinating? to seek basic help from them.
Flexible numeric types. Although you can be specific about numeric types in MATLAB when you really want, by default every number is potentially a complex float. While stricter numerical types are important for writing applications, they can get in the way for casual and new users.
It’s not easy to anticipate, for example, that initializing a vector of Newton iterates with
1will lead to an error when you later try to push a float into that vector, and the
InexactErrormessage you get is cryptic at best. For the initiated, it’s a trivial thing to use
0.or cast with
floatat the start, and to recognize the source of the problem if you forget. But for students grappling with larger math and computing concepts, every bit of cognitive load and frustrating experience takes a toll.
Pass by value vs. reference. Ask a student whether MATLAB passes matrices by value or by reference, and you will probably get a blank stare. That’s because you simply don’t have to think about the issue at all. It’s not as though it always chooses to pass by value; instead, it analyzes each function, and if the value isn’t changed, the matrix is passed by reference.
I can see why an advanced programmer in search of maximum performance doesn’t want that to happen: if you have to acknowledge the computational effort with an explicit copy operation, you may look harder for ways to avoid it. However, that level of control is meaningless to the beginner.
(And yes, this is fodder for haters of imperative programming, but let’s not fight that battle today.)
Debugging. MATLAB’s debugger is the most valuable feature of its IDE. I’m not often able to get students to take advantage of it, but maybe that’s on me. Julia has made great strides in providing the capability, notably in the VS code extension. But it’s agonizingly slow, apparently because Julia isn’t meant to be run in an interpreted way.
In Julia’s favor
Broadcasting. This has to be my favorite aspect of both teaching with and using Julia. Some students using MATLAB sort of give up on when and how to vectorize, trying
.*seemingly at random until things work. Julia’s
@.macro makes vectorization conceptually and syntactically simple. Even better, you can now write all your own functions for scalar arguments, because they can all be broadcast after the fact by a single dot, e. g.,
Don’t even get me started on the disaster that MathWorks created by introducing broadcasting for
-operations. It’s easy to lose track of row/column orientation, and now instead of easily fixed errors, you get bizarre results. Worst. Decision. Ever. Guys,
.-were right there!
Function definitions inline. Look, I get it. I remember when MATLAB allowed one function per M-file, period. Things have gotten way better since then. You can even define full-fledged functions within a script, as long as they’re at the bottom of the script. That’s almost everything you could want.
First-class functions. I can remember a talk by Cleve Moler given at Cornell way back in the 20th century, when an audience member asked if a forthcoming version of MATLAB would treat functions as first-class objects. As a whelp, I had no idea what that meant. At that time, if you wanted to use a function as data, you had to pass the function names as a string and then
I believe it was MATLAB 5 that introduced function handles, such as
@foo, to address this problem. The same character was tasked to create inline functions, such as
foo = @(t) sin(cos(t)). It’s all pretty straightforward to programming veterans. But I see a lot of students get confused about when and how to use the
@sign. In retrospect, maybe having one symbol serve both purposes was a mistake.
Vectors are vectors. MATLAB makes no distinction between a vector and a matrix with a singleton dimension. Often row and column vectors are interchangeable, but sometimes the distinction matters, and students have a difficult time predicting when. Ranges created using
:are row vectors, even though most of modern matrix algebra expects column vectors by default. Then there’s the fact that scalars are the same as $1\times 1$ matrices, except there are many edge cases where they are treated differently. The behaviors are usually instinctively correct for the initiated, but newbies can get bollixed up.
In Julia, vectors have one dimension and scalars have none. It’s not quite pure, because in many cases a vector can be used in context as a column vector. But there are no row vectors per se, just adjoints of vectors. I didn’t always like this scheme—I was reluctant to see
A[i,:]as a quasi-column vector—but in time, I have come to appreciate the consistency it brings to the table.
Unicode. It sounds like mere fluff to allow Unicode in variable and function names. However, form matters. There’s a reason why, when we do math, we write π and not “pi”, x̃ and not “x_tilde”, and v₁ and not “v_1”: to be compact and expressive. Being able to make code look more like our math is a subtle but powerful advantage.
Local scopes within loops. I’m shocked that I am including this as an advantage, since it really put me off when Julia 1.0 was released. But consider the following pattern in MATLAB:
n = 50:50:500; x = zeros(size(n)); for i = 1:length(n) ] = euler(f,t,u0,n(i)); = u(end); end
This is fine. But there will be plenty of students who forget to use
n, and if there are multiple expressions using it, things get a little cluttered. A Julia counterpart is
n = 50:50:500 x = zeros(length(n)) for (i,n) in enumerate(n) = euler(f,t,u0,n) = u[end] end
OK, the advantages here look tiny. But wait for the next point.
x = y = range(-1,1,length=60) U = [ exp(x*y)-2y for x in x, y in y ]
Check and mate.
It’s a draw
Graphics. MATLAB’s graphics are still great. They are a bit easier to use, with greater unity of design, than Julia’s offerings. I favor
Plots, which shines at animations. If you like MATLAB’s graphics system, the Matplotlib clone in Python works great in Julia as PyPlot. Still others like Makie, especially to use GPU hardware. The additional choices in Julia, and their extensibility, essentially make up for whatever you might do a little better or easier in MATLAB.
IDE. MATLAB’s desktop IDE is not beautiful or lovable, but it’s powerful and quite flexible. At this point, the VS code extension for Julia is a different animal, and better as a text editor, but this comparison is a wash.
Notebooks. MATLAB has their Live Script format, which is essentially a notebook interface. It’s a bit slow and a walled garden, but it gets the job done. Jupyter notebooks are pretty easy to manage through
IJulia, and they’re fine, though conversion to PDF is easier via browser print than through having to install LaTeX. Interestingly, you can use Jupyter with MATLAB as well, though I’ve never tried to talk students through it.
Both interfaces suffer from the out-of-order execution problem that results from jumping around within the notebook. That can trip up experts, and it can really stymie n00bs.
Pluto.jlis an interesting all-Julian take on notebooks that don’t allow that situation to happen. I like it, but I don’t know how students would respond to it.
Relevance. Julia has a lot of power, a great community, an upward trajectory, and a modern feel. MATLAB is a useful blend of stability and progress, and some engineering disciplines more or less expect it to be available and used. The elephant in the room, of course, is Python. While I prefer both Julia and MATLAB to it for teaching computational math, it’s impossible to ignore the benefit to many students of having more experience in Python.