Noteworthy Differences from other Languages
Noteworthy differences from MATLAB
Although MATLAB users may find Julia's syntax familiar, Julia is not a MATLAB clone. There are major syntactic and functional differences. The following are some noteworthy differences that may trip up Julia users accustomed to MATLAB:
Julia arrays are indexed with square brackets,
A[i,j].Julia arrays are assigned by reference. After
A=B, changing elements ofBwill modifyAas well.Julia values are passed and assigned by reference. If a function modifies an array, the changes will be visible in the caller.
Julia does not automatically grow arrays in an assignment statement. Whereas in MATLAB
a(4) = 3.2can create the arraya = [0 0 0 3.2]anda(5) = 7can grow it intoa = [0 0 0 3.2 7], the corresponding Julia statementa[5] = 7throws an error if the length ofais less than 5 or if this statement is the first use of the identifiera. Julia haspush!()andappend!(), which growVectors much more efficiently than MATLAB'sa(end+1) = val.The imaginary unit
sqrt(-1)is represented in Julia asim, notiorjas in MATLAB.In Julia, literal numbers without a decimal point (such as
42) create integers instead of floating point numbers. Arbitrarily large integer literals are supported. As a result, some operations such as2^-1will throw a domain error as the result is not an integer (see the FAQ entry on domain errors for details).In Julia, multiple values are returned and assigned as tuples, e.g.
(a, b) = (1, 2)ora, b = 1, 2. MATLAB'snargout, which is often used in MATLAB to do optional work based on the number of returned values, does not exist in Julia. Instead, users can use optional and keyword arguments to achieve similar capabilities.Julia has true one-dimensional arrays. Column vectors are of size
N, notNx1. For example,rand(N)makes a 1-dimensional array.In Julia,
[x,y,z]will always construct a 3-element array containingx,yandz.To concatenate in the first ("vertical") dimension use either
vcat(x,y,z)or separate with semicolons ([x; y; z]).To concatenate in the second ("horizontal") dimension use either
hcat(x,y,z)or separate with spaces ([x y z]).To construct block matrices (concatenating in the first two dimensions), use either
hvcat()or combine spaces and semicolons ([a b; c d]).
In Julia,
a:banda:b:cconstructRangeobjects. To construct a full vector like in MATLAB, usecollect(a:b). Generally, there is no need to callcollectthough.Rangewill act like a normal array in most cases but is more efficient because it lazily computes its values. This pattern of creating specialized objects instead of full arrays is used frequently, and is also seen in functions such aslinspace, or with iterators such asenumerate, andzip. The special objects can mostly be used as if they were normal arrays.Functions in Julia return values from their last expression or the
returnkeyword instead of listing the names of variables to return in the function definition (see The return Keyword for details).A Julia script may contain any number of functions, and all definitions will be externally visible when the file is loaded. Function definitions can be loaded from files outside the current working directory.
In Julia, reductions such as
sum(),prod(), andmax()are performed over every element of an array when called with a single argument, as insum(A), even ifAhas more than one dimension.In Julia, functions such as
sort()that operate column-wise by default (sort(A)is equivalent tosort(A,1)) do not have special behavior for1xNarrays; the argument is returned unmodified since it still performssort(A,1). To sort a1xNmatrix like a vector, usesort(A,2).In Julia, if
Ais a 2-dimensional array,fft(A)computes a 2D FFT. In particular, it is not equivalent tofft(A,1), which computes a 1D FFT acting column-wise.In Julia, parentheses must be used to call a function with zero arguments, like in
tic()andtoc().Julia discourages the used of semicolons to end statements. The results of statements are not automatically printed (except at the interactive prompt), and lines of code do not need to end with semicolons.
println()or@printf()can be used to print specific output.In Julia, if
AandBare arrays, logical comparison operations likeA == Bdo not return an array of booleans. Instead, useA .== B, and similarly for the other boolean operators like<,>and=.In Julia, the operators
&,|, and⊻(xor) perform the bitwise operations equivalent toand,or, andxorrespectively in MATLAB, and have precedence similar to Python's bitwise operators (unlike C). They can operate on scalars or element-wise across arrays and can be used to combine logical arrays, but note the difference in order of operations: parentheses may be required (e.g., to select elements ofAequal to 1 or 2 use(A .== 1) | (A .== 2)).In Julia, the elements of a collection can be passed as arguments to a function using the splat operator
..., as inxs=[1,2]; f(xs...).Julia's
svd()returns singular values as a vector instead of as a dense diagonal matrix.In Julia,
...is not used to continue lines of code. Instead, incomplete expressions automatically continue onto the next line.In both Julia and MATLAB, the variable
ansis set to the value of the last expression issued in an interactive session. In Julia, unlike MATLAB,ansis not set when Julia code is run in non-interactive mode.Julia's
types do not support dynamically adding fields at runtime, unlike MATLAB'sclasses. Instead, use aDict.In Julia each module has its own global scope/namespace, whereas in MATLAB there is just one global scope.
In MATLAB, an idiomatic way to remove unwanted values is to use logical indexing, like in the expression
x(x>3)or in the statementx(x>3) = []to modifyxin-place. In contrast, Julia provides the higher order functionsfilter()andfilter!(), allowing users to writefilter(z->z>3, x)andfilter!(z->z>3, x)as alternatives to the corresponding transliterationsx[x.>3]andx = x[x.>3]. Usingfilter!()reduces the use of temporary arrays.The analogue of extracting (or "dereferencing") all elements of a cell array, e.g. in
vertcat(A{:})in MATLAB, is written using the splat operator in Julia, e.g. asvcat(A...).
Noteworthy differences from R
One of Julia's goals is to provide an effective language for data analysis and statistical programming. For users coming to Julia from R, these are some noteworthy differences:
Julia's single quotes enclose characters, not strings.
Julia can create substrings by indexing into strings. In R, strings must be converted into character vectors before creating substrings.
In Julia, like Python but unlike R, strings can be created with triple quotes
""" ... """. This syntax is convenient for constructing strings that contain line breaks.In Julia, varargs are specified using the splat operator
..., which always follows the name of a specific variable, unlike R, for which...can occur in isolation.In Julia, modulus is
mod(a, b), nota %% b.%in Julia is the remainder operator.In Julia, not all data structures support logical indexing. Furthermore, logical indexing in Julia is supported only with vectors of length equal to the object being indexed. For example:
In R,
c(1, 2, 3, 4)[c(TRUE, FALSE)]is equivalent toc(1, 3).In R,
c(1, 2, 3, 4)[c(TRUE, FALSE, TRUE, FALSE)]is equivalent toc(1, 3).In Julia,
[1, 2, 3, 4][[true, false]]throws aBoundsError.In Julia,
[1, 2, 3, 4][[true, false, true, false]]produces[1, 3].
Like many languages, Julia does not always allow operations on vectors of different lengths, unlike R where the vectors only need to share a common index range. For example,
c(1, 2, 3, 4) + c(1, 2)is valid R but the equivalent[1, 2, 3, 4] + [1, 2]will throw an error in Julia.Julia's
map()takes the function first, then its arguments, unlikelapply(<structure>, function, ...)in R. Similarly Julia's equivalent ofapply(X, MARGIN, FUN, ...)in R ismapslices()where the function is the first argument.Multivariate apply in R, e.g.
mapply(choose, 11:13, 1:3), can be written asbroadcast(binomial, 11:13, 1:3)in Julia. Equivalently Julia offers a shorter dot syntax for vectorizing functionsbinomial.(11:13, 1:3).Julia uses
endto denote the end of conditional blocks, likeif, loop blocks, likewhile/for, and functions. In lieu of the one-lineif ( cond ) statement, Julia allows statements of the formif cond; statement; end,cond && statementand!cond || statement. Assignment statements in the latter two syntaxes must be explicitly wrapped in parentheses, e.g.cond && (x = value).In Julia,
<-,<<-and->are not assignment operators.Julia's
->creates an anonymous function, like Python.Julia constructs vectors using brackets. Julia's
[1, 2, 3]is the equivalent of R'sc(1, 2, 3).Julia's
*operator can perform matrix multiplication, unlike in R. IfAandBare matrices, thenA * Bdenotes a matrix multiplication in Julia, equivalent to R'sA %*% B. In R, this same notation would perform an element-wise (Hadamard) product. To get the element-wise multiplication operation, you need to writeA .* Bin Julia.Julia performs matrix transposition using the
.'operator and conjugated transposition using the'operator. Julia'sA.'is therefore equivalent to R'st(A).Julia does not require parentheses when writing
ifstatements orfor/whileloops: usefor i in [1, 2, 3]instead offor (i in c(1, 2, 3))andif i == 1instead ofif (i == 1).Julia does not treat the numbers
0and1as Booleans. You cannot writeif (1)in Julia, becauseifstatements accept only booleans. Instead, you can writeif true,if Bool(1), orif 1==1.Julia does not provide
nrowandncol. Instead, usesize(M, 1)fornrow(M)andsize(M, 2)forncol(M).Julia is careful to distinguish scalars, vectors and matrices. In R,
1andc(1)are the same. In Julia, they can not be used interchangeably. One potentially confusing result of this is thatx' * yfor vectorsxandyis a 1-element vector, not a scalar. To get a scalar, usedot(x, y).Julia cannot assign to the results of function calls on the left hand side of an assignment operation: you cannot write
diag(M) = ones(n).Julia discourages populating the main namespace with functions. Most statistical functionality for Julia is found in packages under the JuliaStats organization. For example:
Functions pertaining to probability distributions are provided by the Distributions package.
The DataFrames package provides data frames.
Generalized linear models are provided by the GLM package.
Julia provides tuples and real hash tables, but not R-style lists. When returning multiple items, you should typically use a tuple: instead of
list(a = 1, b = 2), use(1, 2).Julia encourages users to write their own types, which are easier to use than S3 or S4 objects in R. Julia's multiple dispatch system means that
table(x::TypeA)andtable(x::TypeB)act like R'stable.TypeA(x)andtable.TypeB(x).In Julia, values are passed and assigned by reference. If a function modifies an array, the changes will be visible in the caller. This is very different from R and allows new functions to operate on large data structures much more efficiently.
In Julia, vectors and matrices are concatenated using
hcat(),vcat()andhvcat(), notc,rbindandcbindlike in R.In Julia, a range like
a:bis not shorthand for a vector like in R, but is a specializedRangethat is used for iteration without high memory overhead. To convert a range into a vector, usecollect(a:b).Julia's
max()andmin()are the equivalent ofpmaxandpminrespectively in R, but both arguments need to have the same dimensions. Whilemaximum()andminimum()replacemaxandminin R, there are important differences.Julia's
sum(),prod(),maximum(), andminimum()are different from their counterparts in R. They all accept one or two arguments. The first argument is an iterable collection such as an array. If there is a second argument, then this argument indicates the dimensions, over which the operation is carried out. For instance, letA=[[1 2],[3 4]]in Julia andB=rbind(c(1,2),c(3,4))be the same matrix in R. Thensum(A)gives the same result assum(B), butsum(A, 1)is a row vector containing the sum over each column andsum(A, 2)is a column vector containing the sum over each row. This contrasts to the behavior of R, wheresum(B,1)=11andsum(B,2)=12. If the second argument is a vector, then it specifies all the dimensions over which the sum is performed, e.g.,sum(A,[1,2])=10. It should be noted that there is no error checking regarding the second argument.Julia has several functions that can mutate their arguments. For example, it has both
sort()andsort!().In R, performance requires vectorization. In Julia, almost the opposite is true: the best performing code is often achieved by using devectorized loops.
Julia is eagerly evaluated and does not support R-style lazy evaluation. For most users, this means that there are very few unquoted expressions or column names.
Julia does not support the
NULLtype.Julia lacks the equivalent of R's
assignorget.In Julia,
returndoes not require parentheses.In R, an idiomatic way to remove unwanted values is to use logical indexing, like in the expression
x[x>3]or in the statementx = x[x>3]to modifyxin-place. In contrast, Julia provides the higher order functionsfilter()andfilter!(), allowing users to writefilter(z->z>3, x)andfilter!(z->z>3, x)as alternatives to the corresponding transliterationsx[x.>3]andx = x[x.>3]. Usingfilter!()reduces the use of temporary arrays.
Noteworthy differences from Python
Julia requires
endto end a block. Unlike Python, Julia has nopasskeyword.In Julia, indexing of arrays, strings, etc. is 1-based not 0-based.
Julia's slice indexing includes the last element, unlike in Python.
a[2:3]in Julia isa[1:3]in Python.Julia does not support negative indexes. In particular, the last element of a list or array is indexed with
endin Julia, not-1as in Python.Julia's
for,if,while, etc. blocks are terminated by theendkeyword. Indentation level is not significant as it is in Python.Julia has no line continuation syntax: if, at the end of a line, the input so far is a complete expression, it is considered done; otherwise the input continues. One way to force an expression to continue is to wrap it in parentheses.
Julia arrays are column major (Fortran ordered) whereas NumPy arrays are row major (C-ordered) by default. To get optimal performance when looping over arrays, the order of the loops should be reversed in Julia relative to NumPy (see relevant section of Performance Tips).
Julia's updating operators (e.g.
+=,-=, ...) are not in-place whereas NumPy's are. This meansA = ones(4); B = A; B += 3doesn't change values inA, it rather rebinds the nameBto the result of the right- hand sideB = B + 3, which is a new array. UseB[:] += 3, explicit loops, orInplaceOps.jl.Julia evaluates default values of function arguments every time the method is invoked, unlike in Python where the default values are evaluated only once when the function is defined. For example, the function
f(x=rand()) = xreturns a new random number every time it is invoked without argument. On the other hand, the functiong(x=[1,2]) = push!(x,3)returns[1,2,3]every time it is called asg().In Julia
%is the remainder operator, whereas in Python it is the modulus.
Noteworthy differences from C/C++
Julia arrays are indexed with square brackets, and can have more than one dimension
A[i,j]. This syntax is not just syntactic sugar for a reference to a pointer or address as in C/C++. See the Julia documentation for the syntax for array construction (it has changed between versions).In Julia, indexing of arrays, strings, etc. is 1-based not 0-based.
Julia arrays are assigned by reference. After
A=B, changing elements ofBwill modifyAas well. Updating operators like+=do not operate in-place, they are equivalent toA = A + Bwhich rebinds the left-hand side to the result of the right-hand side expression.Julia arrays are column major (Fortran ordered) whereas C/C++ arrays are row major ordered by default. To get optimal performance when looping over arrays, the order of the loops should be reversed in Julia relative to C/C++ (see relevant section of Performance Tips).
Julia values are passed and assigned by reference. If a function modifies an array, the changes will be visible in the caller.
In Julia, whitespace is significant, unlike C/C++, so care must be taken when adding/removing whitespace from a Julia program.
In Julia, literal numbers without a decimal point (such as
42) create signed integers, of typeInt, but literals too large to fit in the machine word size will automatically be promoted to a larger size type, such asInt64(ifIntisInt32),Int128, or the arbitrarily largeBigInttype. There are no numeric literal suffixes, such asL,LL,U,UL,ULLto indicate unsigned and/or signed vs. unsigned. Decimal literals are always signed, and hexadecimal literals (which start with0xlike C/C++), are unsigned. Hexadecimal literals also, unlike C/C++/Java and unlike decimal literals in Julia, have a type based on the length of the literal, including leading 0s. For example,0x0and0x00have typeUInt8,0x000and0x0000have typeUInt16, then literals with 5 to 8 hex digits have typeUInt32, 9 to 16 hex digits typeUInt64and 17 to 32 hex digits typeUInt128. This needs to be taken into account when defining hexadecimal masks, for example~0xf == 0xf0is very different from~0x000f == 0xfff0. 64 bitFloat64and 32 bitFloat32bit literals are expressed as1.0and1.0f0respectively. Floating point literals are rounded (and not promoted to theBigFloattype) if they can not be exactly represented. Floating point literals are closer in behavior to C/C++. Octal (prefixed with0o) and binary (prefixed with0b) literals are also treated as unsigned.String literals can be delimited with either
"or""","""delimited literals can contain"characters without quoting it like"\""String literals can have values of other variables or expressions interpolated into them, indicated by$variablenameor$(expression), which evaluates the variable name or the expression in the context of the function.//indicates aRationalnumber, and not a single-line comment (which is#in Julia)#=indicates the start of a multiline comment, and=#ends it.Functions in Julia return values from their last expression(s) or the
returnkeyword. Multiple values can be returned from functions and assigned as tuples, e.g.(a, b) = myfunction()ora, b = myfunction(), instead of having to pass pointers to values as one would have to do in C/C++ (i.e.a = myfunction(&b).Julia does not require the use of semicolons to end statements. The results of expressions are not automatically printed (except at the interactive prompt, i.e. the REPL), and lines of code do not need to end with semicolons.
println()or@printf()can be used to print specific output. In the REPL,;can be used to suppress output.;also has a different meaning within[ ], something to watch out for.;can be used to separate expressions on a single line, but are not strictly necessary in many cases, and are more an aid to readability.In Julia, the operator
⊻(xor) performs the bitwise XOR operation, i.e.^in C/C++. Also, the bitwise operators do not have the same precedence as C/++, so parenthesis may be required.Julia's
^is exponentiation (pow), not bitwise XOR as in C/C++ (use⊻, orxor, in Julia)Julia has two right-shift operators,
>>and>>>.>>>performs an arithmetic shift,>>always performs a logical shift, unlike C/C++, where the meaning of>>depends on the type of the value being shifted.Julia's
->creates an anonymous function, it does not access a member via a pointer.Julia does not require parentheses when writing
ifstatements orfor/whileloops: usefor i in [1, 2, 3]instead offor (int i=1; i <= 3; i++)andif i == 1instead ofif (i == 1).Julia does not treat the numbers
0and1as Booleans. You cannot writeif (1)in Julia, becauseifstatements accept only booleans. Instead, you can writeif true,if Bool(1), orif 1==1.Julia uses
endto denote the end of conditional blocks, likeif, loop blocks, likewhile/for, and functions. In lieu of the one-lineif ( cond ) statement, Julia allows statements of the formif cond; statement; end,cond && statementand!cond || statement. Assignment statements in the latter two syntaxes must be explicitly wrapped in parentheses, e.g.cond && (x = value), because of the operator precedence.Julia has no line continuation syntax: if, at the end of a line, the input so far is a complete expression, it is considered done; otherwise the input continues. One way to force an expression to continue is to wrap it in parentheses.
Julia macros operate on parsed expressions, rather than the text of the program, which allows them to perform sophisticated transformations of Julia code. Macro names start with the
@character, and have both a function-like syntax,@mymacro(arg1, arg2, arg3), and a statement-like syntax,@mymacro arg1 arg2 arg3. The forms are interchangable; the function-like form is particularly useful if the macro appears within another expression, and is often clearest. The statement-like form is often used to annotate blocks, as in the parallelforconstruct:@parallel for i in 1:n; #= body =#; end. Where the end of the macro construct may be unclear, use the function-like form.Julia now has an enumeration type, expressed using the macro
@enum(name, value1, value2, ...)For example:@enum(Fruit, banana=1, apple, pear)By convention, functions that modify their arguments have a
!at the end of the name, for examplepush!.In C++, by default, you have static dispatch, i.e. you need to annotate a function as virtual, in order to have dynamic dispatch. On the other hand, in Julia every method is "virtual" (although it's more general than that since methods are dispatched on every argument type, not only
this, using the most-specific-declaration rule).