Julia's Error Message for String Concatenation
I've been learning Julia recently. I was sick in bed and spent three straight hours reading the Julia manual from beginning to end.
After that initial mental download, now I've been using the language.
Recently I tried to concatenate two string literals. I tried this first:
julia> "a","b"
("a", "b")
How about +
then?
julia> "a"+"b"
ERROR: MethodError: no method matching +(::String, ::String)
String concatenation is performed with * (See also: https://docs.julialang.org/en/v1/manual/strings/#man-concatenation).
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...)
@ Base operators.jl:587
Stacktrace:
[1] top-level scope
@ REPL[2]:1
🥹
Now by this point I'd seen that Julia provides good error messages. Almost every error message I've seen so far has these awesome qualities:
- It shows you the signature of what you tried, which in this case is trivial to see, but when the arguments are variable references, this type information is extremely helpful and contextualized in the method signature.
- It shows you closest candidate methods based on the argument types you provided. Maybe you reversed your arguments, or the method expects a collection instead of a scalar, etc. This saves time, and I learn about other signatures and therefore use-cases for methods passively.
- It includes a readable stack trace.
But this particular error message takes it one step further with the new
language learner in mind and points out that I've made an understandable,
common mistake based on how +
is used in other languages:
String concatenation is performed with * (See also: https://docs.julialang.org/en/v1/manual/strings/#man-concatenation).
Look at that! It told me the right method to use, and it provided a link to Julia's documentation.
I almost slapped *
in my code and moved on, but I had to know
more. I've studied tons of languages and seen a lot of ways to
concatenate strings, but I'd never encountered *
for string
concatenation.
So I cracked open the documentation link and was not disappointed:
While
*
may seem like a surprising choice to users of languages that provide+
for string concatenation, this use of*
has precedent in mathematics, particularly in abstract algebra.In mathematics,
+
usually denotes a commutative operation, where the order of the operands does not matter. An example of this is matrix addition, whereA + B == B + A
for any matricesA
andB
that have the same shape. In contrast,*
typically denotes a noncommutative operation, where the order of the operands does matter. An example of this is matrix multiplication, where in generalA * B != B * A
. As with matrix multiplication, string concatenation is noncommutative:greet * whom != whom * greet
. As such,*
is a more natural choice for an infix string concatenation operator, consistent with common mathematical use.More precisely, the set of all finite-length strings
S
together with the string concatenation operator*
forms a free monoid(S, *)
. The identity element of this set is the empty string,""
. Whenever a free monoid is not commutative, the operation is typically represented as\cdot
,*,
or a similar symbol, rather than+,
which as stated usually implies commutativity.
The bar has been raised, gentlefolk.
A big "thank you" to the language implementers of Julia, Rust, Zig, and other languages that have conscientiously implemented information-rich error messages that ease the learning curve for the humans encountering them.