The second example shows that the result of sub2ind
might be very buggy in some specific cases.
Julia’s metaprogramming features are heavily inspired by those of Lisp-like languages, and will seem familiar to those with some Lisp background. Metaprogramming is very powerful. When used correctly, it can lead to more concise and readable code.
The quote ... end
is quasiquote syntax. Instead of the expressions within being evaluated, they are simply parsed. The value of the quote ... end
expression is the resulting Abstract Syntax Tree (AST).
The :(...)
syntax is similar to the quote ... end
syntax, but it is more lightweight. This syntax is more concise than quote ... end
.
Inside a quasiquote, the $
operator is special and interpolates its argument into the AST. The argument is expected to be an expression which is spliced directly into the AST.
The Meta.quot(x)
function quotes its argument. This is often useful in combination with using $
for interpolation, as it allows expressions and symbols to be spliced literally into the AST.
Aside from generic functions (which are most common), there are also built-in functions. Such functions include is
, isa
, typeof
, throw
, and similar functions. Built-in functions are typically implemented in C instead of Julia, so they cannot be specialized on argument types for dispatch.
Whenever it makes code shorter and easier to read, consider using higher-order functions, such as map
or filter
, instead of loops.
All conditional operators and functions involve using boolean conditions (true
or false
). In Julia, the type of booleans is Bool
. Unlike some other languages, other kinds of numbers (like 1
or 0
), strings, arrays, and so forth cannot be used directly in conditionals.
Typically, one uses either predicate functions (functions that return a Bool
) or comparison operators in the condition of a conditional operator or function.
Types are key to Julia's performance. An important idea for performance is type stability, which occurs when the type a function returns only depends on the types, not the values, of its arguments.
Since neither Julia Dict
nor JSON objects are inherently ordered, it's best not to rely on the order of key-value pairs in a JSON object.
Be careful about flipping comparison signs around. Julia defines many comparison functions by default without defining the corresponding flipped version. For instance, one can run
julia> Set(1:3) ⊆ Set(0:5)
true
but it does not work to do
julia> Set(0:5) ⊇ Set(1:3)
ERROR: UndefVarError: ⊇ not defined
Overuse or inappropriate use of advanced control flow makes code hard to read. @goto
or its equivalents in other languages, when used improperly, leads to unreadable spaghetti code.
Similar to languages like C, one cannot jump between functions in Julia. This also means that @goto
is not possible at the top-level; it will only work within a function. Furthermore, one cannot jump from an inner function to its outer function, or from an outer function to an inner function.
The while
loop does not have a value; although it can be used in expression position, its type is Void
and the value obtained will be nothing
.
The standard library documentation for Base.Test
covers additional material beyond that shown in these examples.
In older versions of Julia, closures and anonymous functions had a runtime performance penalty. This penalty has been eliminated in 0.5.
Other packages may define their own REPL modes in addition to the default modes. For instance, the Cxx
package defines the cxx>
shell mode for a C++ REPL. These modes are usually accessible with their own special keys; see package documentation for more details.
Although combinators have limited practical use, they are a useful tool in education to understand how programming is fundamentally linked to logic, and how very simple building blocks can combine to create very complex behaviour. In the context of Julia, learning how to create and use combinators will strengthen an understanding of how to program in a functional style in Julia.
String macros are not quite as powerful as plain old strings — because interpolation must be implemented in the macro's logic, string macros are unable to contain string literals of the same delimiter for interpolation.
For instance, although
julia> "$("x")"
"x"
works, the string macro text form
julia> doc"$("x")"
ERROR: KeyError: key :x not found
gets parsed incorrectly. This can be somewhat mitigated by using triple-quotes as the outer string delimiter;
julia> doc"""$("x")"""
"x"
does indeed work properly.
It is sometimes very difficult to get new syntax to play well with multiple versions. As Julia is still undergoing active development, it is often useful simply to drop support for older versions and instead target just the newer ones.
Tuples have much better runtime performance than arrays for two reasons: their types are more precise, and their immutability allows them to be allocated on the stack instead of the heap. However, this more precise typing comes with both more compile-time overhead and more difficulty achieving type stability.
Functions can be accepted as parameters and can also be produced as return types. Indeed, functions can be created inside the body of other functions. These inner functions are known as closures.
It is sometimes useful to have enumerated types where each instance is of a different type (often a singleton immutable type); this can be important for type stability. Traits are typically implemented with this paradigm. However, this results in additional compile-time overhead.