Julia for prototyping, compared to MATLAB?

For instance, just consider that you cannot directly access an array that is returned from a function.

How?

1 Like

Matlab:

function [a] = f(a, b, i)
a(i) = b;
end

This cannot be done:

a = [0, 3, 5]
f(a, 1, 1)(1)

In Julia:

a = [0, 3, 5]
f(a, b, i) = (a[i] = b)
f(a, 1, 1)[1]
2 Likes

I see, this is fascinating. Is there any source, where I can find this sort of Julia/MATLAB differences?

https://docs.julialang.org/en/v1/manual/noteworthy-differences/index.html

4 Likes

Implicit expansion: http://hogwarts.ucsd.edu/~pkrysl/no-Matlab-support.html

8 Likes

I’m a Matlab user since R2012 and I can say it was my first programming language I really used (did some C in college). Here’s my take on Matlab:

One of the things I started to hate about Matlab, after trying Julia, is the lack of namespaces. It has only one “global” namespace and every time you want to make some code available you need to “add it to the path”. This is very risky if you work with different codebases which can conflict with each other.(Matlab has classes and that can alleviate the problem a little, but it’s not as expressive as Julia’s multiple dispatch).

It’s hard to envision these kind of things if Matlab is your only background(as it was my case) and you learn to dance around them, but once you try something else(Julia in this case, Python is similar, but I like Julia’s Pkg much more), you start to realize that there is big world with lots of goodies. This “ease of use” that Matlab promotes is a double edged sword, because as codebases grow, they are harder to maintain and people are educated with the mentality of “everything in one place”(everything in one huge script, everything in one huge repo).

Another cool point in Julia is the keyword arguments of functions and the default values for arguments. This is something that drives me crazy when I use Matlab now, because I have to clutter my code with a lot of if, else, for loops over varargin or even worse, use the horrific input parser.

Then I could add Julia’s consistency when using broadcasting (you add a dot, you have elementwise operation). Matlab uses the dot notation for vectorization, but there are a lot of cases where it broadcasts automatically even if the user didn’t write the code like that. Some might call that convenience, I call it confusing.

You can sort of do metaprogramming in Matlab using the “eval”, but it will be painfully slow and it’s not advised. Julia has efficient macros.

Matlab lacks basic types like tuples and dictionaries (it recently added containers.Map to mimic a dict)

Then there is the hilarious choice of Matlab to output line vectors out of a lot of built-in/user functions, although the language is column major. This forces me to add a lot of checks in my functions to see if my array is a column.

I could go on, but my 2c is that one needs to try stuff in both languages to see their advantages and drawbacks. For me Julia was in eye opener.

11 Likes

And this is really only for .*, .^ and ./, you can’t vectorize arbitrary functions or operators.

11 Likes

The implicit expansion thing is a great example.

To be clear, implicit expansion is an extremely useful tool to save a bunch of ugly bsxfun(...)s littering your code. In a language that demands vectorization for performance code, it totally makes sense why they would introduce it. But… it’s also a terrible source of hidden bugs and code obfuscation, as this link points out.

What you need is something that handles broadcasting that

  1. has as small of a syntax footprint as possible,
  2. is opt-in so it is always clear when you are broadcasting, and
  3. throws an error when incompatible sizes are used without broadcasting.

This is why Julia’s dot broadcasting syntax is so cool. If a is a length-3 vector and B is a 3x3 matrix, a .+ B will broadcast a to the higher dimension and a + B will throw an error. All three of the above requirements are met. And Julia doesn’t even need to use broadcasting to have fast code.

5 Likes

Yes! This hit just about all of my worst pain points. Built-in functions sometimes returning row vectors and sometimes column (and having to constantly check for this), containers.Map almost never does what I want it to, and the input parser is just the worth thing ever (and that is the best way to handle keyword arguments in MATLAB).

I’ll add to the list that cell arrays have to be accessed with different syntax than arrays, so I’m constantly writing if iscell(...). This Is especially bad with the whole char arrays as pseudo-strings thing (and now they have real strings, so there is always going to be the issue of supporting both).

Also, for loops only iterate over a vector if it’s a row vector and pass the whole vector in as a loop variable if it’s a column vector. This combined with not knowing whether you ever have row or column vectors due to the point above makes the nice for thing=things syntax that is common in Python and Julia pretty dangerous, even though it’s supported.

3 Likes

Here are some points, off the top of my head. Several of them overlap with points raised by other posters:

  • Functions need own file in Matlab and all files in path intrude in namespace

Whenever you want to define a function, you can’t do it from the command line, or inside a script (except with some major limitations)

  • Dispatch vs input parsing

Input parsing in Matlab is a nightmare. You have the inputParser class now, but it seems really heavy and awkward.

  • Default values and keyword arguments

This is related to the above. You can `fake’ keyword arguments using two consecutive inputs, one string for the keyword and one for the value. It’s an awful kludge.

  • Everything in Matlab is a matrix (or a higher dimensional array)

You can’t have scalars, so you always have to consider the ramifications of the fact that your value is a container with a shape and linear algebra-like behaviour. Often you want your code to behave one way if it’s a `scalar’ and another if it’s a vector and a third if it’s a matrix. But it’s always a matrix, and it requires a lot of awkward tests and planning. (Is a single number a scalar, is it a vector or is it a matrix?)

  • Possible to mutate objects (no copy on assignment)

When you assign to a variable, the object you assign is copied. So you cannot pass an array into a function to mutate it (Matlab can only somtimes mutate as an optimization if certain cases). Mutation is supported for user classes that inherit from the handle class.

  • Julia can define functions like +() and *()

It’s great!

  • Direct access to objects with indexing for example

a[i][j] or foo(x)[1] etc are impossible in Matlab, so you must create intermediate variables.

  • Better handling of variable inputs and outputs with splat and slurp

varargin and varargout in Matlab is an annoying mess to work with.

  • Much better iterators

Matlab doesn’t have proper iterators, so you will normally have to do for n = 1:length(x). You can in principle write for val in x, but it only works for 1xN vectors, not Nx1. For a matrix each iteration will actually return a column of x.

  • 1d vectors avoid orientation confusion

Column major language, but almost all internal functions return row vectors. Also, iteration only works for row vectors, as mentioned. Proper flat 1D vectors are amazing.

  • Map and broadcast vs cellfun, arrayfun, structfun, bsxfun

Vectorizing code is the major coding style in Matlab, but it’s so inconvenient. You have no general map function, let alone the awsome broadcasting (you have a really pale type of broadcasting that works for +-*/). Instead you have different and awkward functions, cellfun, arrayfun and structfun for different types of collections.

  • foo is a function call

You don’t have to use parens for a function call, so you cannot tell if foo is a variable or a function call. Passing functions around requires using @ to create a ``function handle’’.

  • Creating empty containers of specific class is awkward in matlab

Due to everything being a matrix it is actually really hard to create empty arrays of objects. I struggled to implement this for some classes recently. You can do it, but it’s messy, verbose and hard to understand.

  • Poor support for hash tables/dictionary

There’s containers.Map which noone uses.

  • Generators and comprehensions

These are incredible, and there’s nothing like it in Matlab.

  • Explicit multithreading

Nope.

  • char arrays and strings in matlab

This is a big mess. Previously strings were char arrays, and they are still what is mostly used throughout the language. Now they have more proper strings, but they are barely used, and also, of course a string is always a [1x1] string array. I can’t really go into this, but it is awkward.

  • Operations that only accept small number of input types.

This is a common problem in most programming languages, except Julia, as far as I can tell. ``Sorry, this function only accepts double floats.’’

14 Likes

As @balinus wrote, the prototyping/exploration phase can often be badly slowed down by the computing time required by the numerical experiments to complete. I have witnessed too many times laptops moaning in (relative) silence while they were bravely trying to complete probabilistic computations for hours/days/nights (usually on a single thread).

Such quantity of wasted computing (and electrical) power drives me several time to write C++ kernels for MATLAB users. I may have felt proud and marginally useful doing so :wink:

With Julia, the very same mathematicians/scientists can reach high performances on their own. So, probabilists’s laptops of the world say (in their chest) thank you Julia !

2 Likes

Unless they are subfunctions to the main function in the file, in which case you instead cannot access them outside of the main function, making unit testing of those subfunctions a major pain. (Actually I found a way to retrieve subfunction pointers, but it’s most horrible hack I’ve ever done.)

Disclaimer, I haven’t followed Matlab developments since ~2014 so maybe there’s a solution to this problem now.

1 Like

Not that difficult to workaround

function  varargout = mylib(fun_name,varargin)
	if (nargout)
		[varargout{1:nargout}] = feval(fun_name, varargin{:});
	else
		feval(fun_name, varargin{:});
	end

function fun1
function fun2
...

and call it like

out = mylib('fun1', args);

That appears to be an extraordinarily unpleasant way of defining functions.

2 Likes

It was not meant to be pleasant but to make possible a case that is otherwise not in Matlab

I understand, it’s a clever hack :slightly_smiling_face: It’s a nice example of what people work out to workaround shortcomings of the language. The fact that you worked out such a solution emphasises how severely limited the matlab language is.

1 Like

The preferred way to handle namespacing in MATLAB is to put the functions you want (all as separate files) in a folder that starts with ‘+’. So you would have fun1.m and fun2.m in a +mylib folder then you can call mylib.fun1(...). To be honest, I don’t find it as awful as everyone else seems to. I mean, it is a little annoying that you have to have all of your externally callable functions in separate files, but in the large space of my MATLAB gripes, this one takes up a pretty small corner.

1 Like

I think it’s pretty annoying for interactive work, when I just want to define a throw-away function. The overhead of coming up with a name and a location to store the file, and make it available, but avoid all the other old throw-away functions you made, is to me similar to the annoyance of having to come up with a username/password combination for throw-away accounts (that is, the overhead is pretty big.)

2 Likes

Thanks for bringing this thread back alive—I am still learning (and struggling) a lot, but the slack channel really helps with random small questions that I need to ask on a daily basis. My feelings so far: I love the syntax and the community, and when Julia works I am very happy. But often I am frustrated by what I feel “non-programming” issues (which isn’t true, but I am used to MATLAB’s “works out of the box” paradigm), like something breaking, no knowing how to get something to work, developing packages, managing paths, etc. For example, right now I got my analysis script running and formatted nicely but I can’t get weave.jl to produce a report I need to submit (some issue with plotly backend plots not being generated).

I recently bought the book Hands-on Design Patterns and Best Practices with Julia by @tk3369 to get a feel for, as you said “modern software engineering and workflow”. It is not specifically for MATLAB users, and is not a beginner book, but from what I read from the preface seems to cover general principles that are applicable in all domains. I’ve only read it for a day, so can’t vouch for it yet but the general tone of the book is very gentle and encouraging.

I’d love to hear from @tk3369 about what he feels about people coming from propriety languages such as MATLAB and how we can make the journey to effectively using Julia as smooth as possible.

5 Likes

Hey @ElectronicTeaCup, thanks for the tag.

Unfortunately, I am not a Matlab user and I can’t quite feel the pain that everyone else went through. On the other hand, I am always amazed that many people in this community can write very good code even without any computer science background.

I cannot say whether it works for everyone but I can definitely share how I learned Julia:

  1. Get on the REPL often and do small experiments
  2. Learn to use development/productivity tools e.g. VSCode, Revise, etc.
  3. Build a package and register it. It can be a small thing and that’s ok.
  4. Write unit tests and enable CI checks e.g. Travis, codecov, etc.
  5. Read other people’s code e.g. there are some real good ones from Invenia.
  6. Ask a lot of questions. There are no dumb questions. Sometimes your question leads to very interesting discussions.
  7. Write a blog post about what I learned.
  8. Try to help others out in public channels/forums (and be surprised when someone else comes up with a better answer.)
  9. Have some fun playing online contests e.g. advent of code, CTF’s.
  10. Try to follow conversations on Slack, Discourse, etc. for topics that I don’t understand or familiar with.

Let me tell you my favorite story. While reading some string manipulation code in Base during my 2nd month of learning Julia, I came across a bug in rstrip and I reported it here. It led to a constructive motivational reply for making a PR. The thread went on about what the correct fix should be. Eventually, I got excited and submitted a two-line fix. It feels good to contribute to Base :slight_smile: If I can do it, you can do it, too.

Hope it helps.

Tom

10 Likes