Introducing Julia/The REPL
The REPL
editThe julia
program starts the interactive REPL, the Read/Evaluate/Print/Loop, by default. It lets you type expressions in Julia code and see the results of the evaluation printed on the screen immediately. It:
- Reads what you type;
- Evaluates it;
- Prints out the return value; then
- Loops back and does it all over again.
The REPL is a great place to start experimenting with the language. But it's not the best environment to do serious programming work of any scale – for that, a text editor, or interactive notebook environment (e.g. IJulia/Jupyter) is a better choice. But there are advantages to using the REPL: it's simple, and should work without any installation or configuration. There's a built-in help system, too.
Using the REPL
editYou type some Julia code and then press Return/Enter. Julia evaluates what you typed and returns the result:
julia> 42 <Return/Enter> 42 julia>
If you're using the Jupyter (IPython) notebook, you probably have to type Control-Enter, or Shift-Enter.
If you don't want to see the result of the expression printed, use a semicolon at the end of the expression:
julia> 42; julia>
Also, if you want to access the value of the last expression you typed on the REPL, it's stored within the variable ans
:
julia> ans 42
If you don't complete the expression on the first line, continue typing until you finish. For example:
julia> 2 + <Return/Enter>
now Julia waits patiently until you finish the expression:
2 <Return/Enter>
and then you'll see the answer:
4 julia>
Help and searching for help
editType a question mark ?
julia> ?
and you'll immediately switch to Help mode, and the prompt changes to yellow (in the terminal):
help?>
Now you can type the name of something (function names should be written without parentheses):
help?> exit search: exit atexit textwidth process_exited method_exists indexin nextind IndexLinear TextDisplay istextmime exit(code=0) Stop the program with an exit code. The default exit code is zero, indicating that the program completed successfully. In an interactive session, exit() can be called with the keyboard shortcut ^D. julia>
Notice that the help system has tried to find all the words that match the letters you typed, and shows you what it found.
If you want to search the documentation, you can use apropos
and a search string:
julia> apropos("determinant") LinearAlgebra.det LinearAlgebra.logabsdet LinearAlgebra.logdet
You'll see a list of functions whose names or descriptions contain the string.
julia> apropos("natural log") Base.log Base.log1p help?> log search: log log2 log1p log10 logging logspace Clong Clonglong Culong Culonglong task_local_storage log(b,x) Compute the base b logarithm of x. Throws DomainError for negative Real arguments.
and so on.
Shell mode
editIf you type a semicolon
julia> ;
you immediately switch to shell mode:
shell>
(And the prompt changes to red). The commands available within this mode are the ones used by your system's command-line shell. In shell mode you can type any shell (i.e., non-Julia) command and see the result:
shell> ls file.txt executable.exe directory file2.txt
How you leave shell mode depends on your Julia version:
- In Julia 1.6 and later, shell mode is "sticky" (persistent). Press Backspace as the first character, or CTRL+C, to go back to the
julia>
prompt - In earlier Julia versions, the prompt switches immediately back to
julia>
, so you have to type a semicolon every time you want to give a shell command.
Package mode
editIf you type a right bracket as the first character:
julia> ]
you immediately switch to Package mode:
(v1.1) pkg>
This is where you carry out package management tasks such as adding packages, testing them, and so on.
To leave package mode press Backspace or CTRL+C on an otherwise empty line.
Orientation
editHere are some other useful interactive functions and macros available at the REPL-prompt:
varinfo()
– prints information about the exported global variables in a module
julia> varinfo() name size summary –––––––––––––––– ––––––––––– ––––––––––– Base Module Core Module InteractiveUtils 222.893 KiB Module Main Module ans 1.285 KiB Markdown.MD
@which
– tells you which method will be called for a function and particular arguments:
julia> @which sin(3) sin(x::Real) in Base.Math at special/trig.jl:53
versioninfo()
– gets Julia version and platform information:
julia> versioninfo() Julia Version 1.1.0 Commit 80516ca202 (2019-01-21 21:24 UTC) Platform Info: OS: Linux (x86_64-pc-linux-gnu) CPU: Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz WORD_SIZE: 64 LIBM: libopenlibm LLVM: libLLVM-6.0.1 (ORCJIT, ivybridge)
There's also a quick way to find out the version:
julia> VERSION v"1.1.0"
edit("pathname")
– launch the default editor and open the filepathname
for editing
@edit rand()
– launch the default editor and open the file containing the definition of the built-in functionrand()
less("filename-in-current-directory")
– displays the file in the pager
clipboard("stuff")
– copies "stuff" to the system clipboard
clipboard()
– pastes the contents of the clipboard into the current REPL line
dump(x)
– displays information about a Julia objectx
on the screen
names(x)
– gets an array of the names exported by the modulex
fieldnames(typeof(x))
– gets an array of the data fields that belong to a symbol of typex
The <TAB>
key: autocompletion
edit
The TAB key is usually able to complete – or suggest a completion for – something whose name you start typing. For example, if I type w
and then press the TAB key (press twice when there are multiple options), all the functions that are currently available beginning with 'w' are listed:
julia> w <TAB> wait walkdir which while widemul widen withenv write
This works both for Julia entities and in shell and package modes. Here, for example, is how I can navigate to a directory from inside Julia:
shell> cd ~ /Users/me shell> cd Doc <TAB> shell> cd Documents/ shell> ls ...
Remember you can get help about functions using ?
and typing in its full name (or using TAB-completion).
TAB-completion also works for Unicode-symbols: eg type \alp
and press TAB to get \alpha
and then press TAB again to get α
. And for Emoji: eg type \:fe
and press TAB to get \:ferris_wheel:
and then press TAB again to get 🎡.
History
editYou can look back through a record of your previous commands using the Up and Down arrow keys (and you can quit and restart without erasing that history). So you don't have to type a long multi-line expression again, because you can just recall it from history. And if you've typed loads of expressions, you can search through them, both back and forwards, by pressing Ctrl-R and Ctrl-S.
Fancy editing
editJulia's REPL supports features that make command-line entry more efficient, and these features are bound to particular key combinations. For example, Alt+b
goes back one word, while Alt+f
goes forward one word. A complete list of key bindings, together with instructions for customizing them, can be found in the REPL documentation. Note that some editors, like VS Code, may override certain key combinations.
Scope and performance
editOne warning about the REPL. The REPL operates at the global scope level of Julia. Usually, when writing longer code, you would put your code inside a function, and organise functions into modules and packages. Julia's compiler works much more effectively when your code is organized into functions, and your code will run much faster as a result. There are also some things that you can't do at the top level – such as specify types for the values of variables.
Changing the prompt and customising your Julia session
editThe following Julia file runs every time you start up Julia (unless you use the startup-file=no
option).
~/.julia/config/startup.jl
This lets you load any package that you know you are going to want later. For example, if you want to customise your REPL session automatically, you can install the Julia package OhMyREPL.jl (https://github.com/KristofferC/OhMyREPL.jl) which lets you customize the REPL's appearance and behaviour, then, in the startup file:
using OhMyREPL
If you just want to set the prompt every time you start a Julia session, you could just add these instructions:
using REPL function myrepl(repl) repl.interface = REPL.setup_interface(repl) repl.interface.modes[1].prompt = "julia-$(VERSION.major).$(VERSION.minor)> " return end atreplinit(myrepl)
This just sets the current REPL prompt to show the Julia version number that your session is using.
Julia and mathematics
editYou can use Julia as a powerful calculator, using the REPL. It's good practice, too. (This is a tradition in introductions to interactive programming languages, and it's a good way to meet the language.)
julia> 1000000 / 7 142857.14285714287
Typing numbers
editHalf the world uses a comma (,) to divide long numbers into groups of three, the other half uses a period (.). (And the rest of us use scientific notation...) In Julia you can use an underscore (_) to separate groups of digits:
julia> 1_000_000 - 2_015 997985
although you won't see one in the response.
To use scientific notation, just type "e" (or "E") and don't add any spaces:
julia> planck_length = 1.61619997e-34
To type imaginary numbers, use im
:
julia> (1 + 0.5im) * 2 2.0 + 1.0im
Operators as functions
editjulia> 2 + 2 4 julia> 2 + 3 + 4 9
An equivalent form for adding numbers is:
julia> +(2, 2) 4
The operators that you usually use between values are ordinary Julia functions, and can be used in the same way as other functions. Similarly:
julia> 2 + 3 + 4 9
can be written as
julia> +(2, 3, 4) 9
and
julia> 2 * 3 * 4 24
can be written as
julia> *(2,3,4) 24
Some maths constants are provided:
julia> pi π = 3.1415926535897...
You can find other maths constants in the MathConstants module:
julia> Base.MathConstants.golden φ = 1.6180339887498... julia> Base.MathConstants.e e = 2.7182818284590...
All the usual operators are available:
julia> 2 + 3 - 4 * 5 / 6 % 7 1.6666666666666665
Notice the precedence of the operators. In this case it's:
((2 + 3) - ((4 * 5) / 6) % 7)
If you want to check the precedence of operators, enclose the expression in :(
and )
:
julia> :(2 + 3 - 4 * 5 / 6 % 7) :((2 + 3) - ((4 * 5) / 6) % 7)
(More on this in Metaprogramming).
Multiplication is usually written *
, but this can be omitted when multiplying a variable by a number literal:
julia> x = 2 2 julia> 2x + 1 5
julia> 10x + 4x - 3x/2 + 1 26.0
This makes equations much easier to write.
You'll sometimes need parentheses to control the evaluation order:
julia> (1 + sqrt(5)) / 2 1.618033988749895
Some others to watch out for include:
^
power%
remainder
To make rational numbers, use two slashes (//
):
julia> x = 666//999 2//3
Technically, /
means "right division." There's also left division "\
". For numbers, x/y
= y\x
. However, for vectors and matrices, x = A\y
solves A*x = y
and x = y/A
solves x*A = y
.
The standard arithmetic operators also have special updating versions, which you can use to update variables quickly:
+=
-=
*=
/=
\=
%=
^=
For example, after defining a variable x
:
julia> x = 5 5
you can add 2 to it:
julia> x += 2 7
then multiply it by 100:
julia> x *= 100 700
and then reduce it to its modulus 11 value:
julia> x %= 11 7
There are element-wise operators which work on arrays. This means that you can multiply two arrays element by element:
julia> [2,4] .* [10, 20] 2-element Array{Int64,1}: 20 80
Arrays are fundamental to Julia, and so have their own chapter in this book.
If you divide two integers using /
, the answer is always a floating-point number. If you've used Python version 2, you'll remember that Python returns an integer result. Python (3) returns a float now.
Julia offers an integer division operator ÷ (type \div TAB
, or use the function version div()
. This should be used when you want an integer result rather than the floating-point returned by /
.
julia> 3 ÷ 2 1 julia> div(3, 2) 1
Notice that Julia doesn't convert the answer to an integer type, even if the result is effectively an integer.
julia> div(3, 2.0) 1.0
This is to avoid type instability problems, which can slow down your code.
Integer overflow
editIf you think your calculations are going to burst out of the 64-bit restriction, choose Big Integers by applying the big
function to store the operands as big numbers:
julia> 2^64 # oops 0 julia> big(2)^64 # better 18446744073709551616 julia> 2^big(64) # equally better 18446744073709551616
To get the fastest execution speeds for your Julia programs, you should be aware of how your data and variables can be stored without introducing 'type instability'.
Number bases
editThese handy utility functions might come in useful when using the REPL as a calculator.
The bitstring()
function shows the literal binary representation of a number, as stored:
julia> bitstring(20.0) "0100000000110100000000000000000000000000000000000000000000000000" julia> bitstring(20) "0000000000000000000000000000000000000000000000000000000000010100"
Notice that the floating point 'version' is, as you would expect, stored differently.
To go from a binary string back to decimal, you can use parse()
, which accepts a target type and number base:
julia> parse(Int, "0000011", base=2) 3 julia> parse(Int, "DecaffBad", base=16) 59805531053
For working in number bases other than the default 10, use the string
function to convert integers to strings:
julia> string(65535, base=16) "ffff" julia> string(64, base=8) "100"
Whereas digits(number, base=b)
returns an array of the digits of number
in the given base:
julia> digits(255, base=16) 2-element Array{Int64,1}: 15 15
Variables
editIn this expression:
julia> x = 3
x
is a variable, a named storage location for a data object. In Julia, variables can be named pretty much how you like, although don't start variable names with numbers or punctuation. You can use Unicode characters, if you want.
To assign a value, use a single equals sign.
julia> a = 1 1 julia> b = 2 2 julia> c = 3 3
To test equality, you should use the ==
operator or isequal()
function.
In Julia, you can also assign multiple variables at the same time:
julia> a, b = 5, 3 (5,3)
Notice that the return value of this expression is a parenthesis-bounded comma-separated ordered list of elements: tuple for short.
julia> a 5 julia> b 3
Multiplying numbers and variables
editIt's worth repeating that you can preface a variable name with a number to multiply them, without having to use an asterisk (*
). For example:
julia> x = 42 42 julia> 2x 84 julia> .5x 21.0 julia> 2pi 6.283185307179586
Special characters
editThe Julia REPL provides easy access to special characters, such as Greek alphabetic characters, subscripts, and special maths symbols. If you type a backslash, you can then type a string (usually the equivalent LATEX string) to insert the corresponding character. For example, if you type:
julia> \sqrt<TAB>
Julia replaces the \sqrt with a square root symbol:
julia> √
Some other examples:
\pi | π |
\Gamma | Γ |
\mercury | ☿ |
\degree | ° |
\cdot | ⋅ |
\in | ∈ |
There's a full list in the Julia source code. As a general principle, in Julia you're encouraged to look at the source code, so there are useful built-in functions for looking at Julia source files. For example, on macOS these symbols are stored in:
julia> less("/Applications/Julia-1.0.app/Contents/Resources/julia/share/julia/stdlib/v1.0/REPL/src/latex_symbols.jl")
less
runs the file through a pager (ie the less
command in Unix). If you're brave, try using edit()
rather than less()
. This launches an editor and opens the file.
It's also possible to use Emoji and other Unicode characters in the REPL.
For emoji, type the Emoji character name, between colons, after the backslash, then press <TAB>:
julia> \:id: <TAB>
which changes to:
julia> 🆔
You can find a list at https://docs.julialang.org/en/latest/manual/unicode-input/#Unicode-Input-1
.
Entering Unicode symbols that aren't in this list is possible but more OS-dependent: on macOS you 'hold down' the Ctrl/Alt key while typing the Unicode hex digits (with the Unicode Hex Input keyboard enabled); on Windows it's Ctrl+Shift+u followed by the hex digits.)
julia> ✎ = 3 3 julia> ✎ 3
Maths functions
editBecause Julia is particularly suited for scientific and technical computing, there are many mathematical functions that you can use immediately, and you often don't have to import them or use prefixes – they're already available.
The trigonometry functions expect values in radians:
julia> sin(pi / 2) 1.0
but there are degree-based versions too: sind(90)
finds the sine of 90 degrees. Use deg2rad()
and rad2deg()
to convert between degrees and radians.
There are also lots of log functions:
julia> log(12) 2.4849066497880004
and the accurate hypot()
function:
julia> hypot(3, 4) 5.0
The norm()
function (after loading via "using LinearAlgebra") returns the "p"-norm of a vector or the operator norm of a matrix. Here's divrem()
:
julia> divrem(13, 3) # returns the division and the remainder (4,1)
There are dozens of others.
There's a system-wide variable called ans
that remembers the most recent result, so that you can use it in the next expression.
julia> 1 * 2 * 3 * 4 * 5 120 julia> ans/10 12.0
Exercise
editGuess, then find out using the help system, what mod2pi()
and isapprox()
do.
Descriptions of all the functions provided as standard with Julia are described here: [1]
Random numbers
editrand()
– gets one random Float64 between 0 and 1
julia> rand() 0.11258244478647295
rand(2, 2)
– an array of Float64s with dimensions 2, 2
rand(type, 2, 2)
– an array of values of this type with dims 2, 2
rand(range, dims)
– array of numbers in a range (including both ends) with specified dimensions:
julia> rand(0:10, 6) 6-element Array{Int64,1}: 6 7 9 6 3 10
(See the Arrays chapter for more about range objects.)
The rand()
function can generate a true or false value if you tell it to, by passing the Bool keyword:
julia> rand(Bool) false
or a bunch of trues and falses:
julia> rand(Bool, 20) 20-element Array{Bool,1}: false true false false false true true false false false false false false false true true false true true false
Random numbers in a distribution
editrandn()
gives you one random number in a normal distribution with mean 0 and standard deviation 1. randn(n)
gives you n such numbers:
julia> randn() 0.8060073309441075 julia> randn(10) 10-element Array{Float64,1}: 1.3261528248041754 1.9203896217047232 -0.17640138484904164 1.0099294365771374 -0.9060606885634369 1.739192165935964 1.375790854463711 -0.6581841725500879 0.11190904953985797 2.798450557786332
If you've installed the Plots plotting package, you can plot this:
julia> using Plots; gr()
julia> histogram(randn(10000), nbins=100)
Seeding the random number generator
editThe Random package contains many more random functions, such as randperm()
, shuffle()
, and seed!
.
Before you use random numbers, you can seed the random number generator with a specific value. This ensures that subsequent random numbers will follow the same sequence, if they start from the same seed. You can seed the generator using the seed!()
or MersenneTwister()
functions.
Once you've added the Random package, you can do:
julia> using Random julia> Random.seed!(10); julia> rand(0:10, 6) 6-element Array{Int64,1}: 6 5 9 1 1 0
julia> rand(0:10, 6) 6-element Array{Int64,1}: 10 3 6 8 0 1
After restarting Julia, the same seed guarantees the same random numbers.
Simple keyboard input
editHere's an example of how you'd write and run a function that reads input from the keyboard:
julia> function areaofcircle() print("What's the radius?") r = parse(Float64, readline(stdin)) print("a circle with radius $r has an area of:") println(π * r^2) end areaofcircle (generic function with 1 method) julia> areaofcircle() What's the radius? 42 a circle with radius 42.0 has an area of: 5541.769440932395 julia>
This works in a Julia REPL session; when called, the function waits for the user to type a string on the keyboard and press Return/Enter.