If you followed through the first part of the chapter, by now you should have a fully functional local Julia installation, the knowledge to start a Julia REPL session, and have your preferred IDE ready for coding. If that is not the case, please refer to the previous sections. From this point on we're getting down to business—it's time to write some Julia code!
Getting started with Julia
The Julia REPL
The first thing we need to understand is how to use the powerful REPL. As a Julia developer, you'll spend a significant amount of time doing exploratory programming, interacting with the shell and the filesystem, and managing packages. The REPL will be your trusted sidekick. It's worth getting to know it well, it will save you a lot of time down the line.
The acronym REPL stands for read-eval-print loop. Simply put, it's a language-specific shell, an interactive coding environment that allows inputting expressions, evaluates them, and outputs the result.
REPLs are very useful as they provide a simple way to interact with the language, to try out ideas and prototype, facilitating exploratory programming and debugging. It is especially powerful in the context of data analysis, where one can quickly connect to a data source, load a data sample and then slice and dice, rapidly testing different hypothesis.
Julia provides an excellent REPL experience, with rich functionality that covers quick evaluation of Julia statements, searchable history, tab-completion, syntax highlighting, dedicated help and shell modes, to name just a few.
If you do not have a working Julia installation, please see the Installing Julia section.
Interacting with the REPL
Depending on your OS and your preferences, the REPL can be started by simply invoking $ julia with no arguments, or by double-clicking the julia executable.
You will be greeted with a screen like this one (the Julia version might be different than mine):
Now Julia is waiting for us to input our code, evaluating it line by line. You can confirm that by checking the Terminal prompt, which says julia>. This is called the julian mode. Let's take it for a spin.
Input the following lines, pressing Enter after each one:
julia> 2+2 julia> 2^3
So we can use Julia like a simple calculator. Not very useful, but this is only the beginning and illustrates how powerful this rapid input and feedback cycle can be when we deal with complex computations.
println is a very useful function that prints whatever value it receives, appending a new line afterward. Type the following code:
julia> println("Welcome to Julia")
Under each line, you should see the output generated by each expression. Your window should now look like this.
julia> 2+2 4
julia> 2^3 8
julia> println("Welcome to Julia") Welcome to Julia
Let's try some more. The REPL interprets one line at a time, but everything is evaluated in a common scope. This means that we can define variables and refer to them later on, as follows:
julia> greeting = "Hello" "Hello"
This looks great! Let's use the greeting variable with println:
julia> println(greting) ERROR: UndefVarError: greting not defined
Oops! A little typo there, and the REPL promptly returned an error. It's not greting, it's greeting. This also tells us that Julia does not allow using variables without properly initializing them. It just looked for the greting variable, unsuccessfully—and it threw an undefined variable error. Let's try that again, this time more carefully:
julia> println(greeting) Hello
OK, that's much better! We can see the output: the Hello value we stored in the greeting variable.
The ans variable
The REPL provides a few helping features, specific to this interactive environment (they won't be available when executing a Julia script). One of these is the ans variable, automatically set up and updated by Julia.
If you type julia> 2^3—unsurprisingly, you'll get 8. Now input julia> ans—you'll get 8 again! What's up with that? ans is a special variable that exists only in the REPL and that automatically stores the last returned value. It can prove very useful when working with the REPL, but more importantly, you need to be aware of its existence so that you don't accidentally declare a variable with the same name. Otherwise, you'll run into some very hard to understand bugs with your variable's value constantly overwritten.
Prompt pasting
The REPL comes with a very powerful feature called prompt pasting. This allows us to copy-paste-execute Julia code and snippets that include both the julia> prompt and the output of the expression. It activates when pasting text that starts with julia>. In that case, only expressions starting with julia> are parsed, and all the others are ignored. This makes it possible to paste a chunk of code that has been copied from another REPL session or from the documentation, without having to scrub away prompts and outputs.
To see this in action, copy and paste the following snippet, as is:
julia> using Dates julia> Dates.now() 2018-09-02T21:13:03.122
julia> ans 2018-09-02T21:13:03.122
If all goes well, both expressions should output your current time, and not the one from the snippet, effectively replacing the results in the snippet with the results in your Julia session.
Tab completion
In both the Julian, pkg, and help modes you can press the Tab key after entering the first few characters of a function to get a list of all the matches:
julia> pri[TAB] primitive type print print_shortest print_with_color println printstyled
It can also be used to substitute LaTeX math symbols with their Unicode equivalents. To do this, type a backslash as the first character, then the first few characters of the symbol, then Tab. This will complete the name of the symbol or will display a list of options if there's more than one matching name. Pressing Tab again on the complete name of the symbol will perform the replacement:
julia> \pi[TAB]
julia> π
π = 3.1415926535897...
julia> \om[TAB] \omega \ominus
julia> \ome[TAB]
julia> \omega[TAB]
julia> ω
Cleaning the REPL scope
Julia does not have the concept of null so you can't really deallocate a variable from memory. If, however, you need to free an expensive resource referenced by a variable, you can replace its value with something like 0 and the previous value will be automatically garbage collected. You can even invoke the garbage collector yourself straight away by calling gc().
Additional REPL modes
The Julia REPL comes with four operational modes—and additional ones can be defined as needed. The currently active mode is indicated by its prompt. In the previous examples we've used the julian mode julia>, which evaluates the inputted expression. The other three available modes are help, help?>, shell, shell>, and package management, pkg>.
The active mode can be switched by typing a specific character right at the beginning of the line. The prompt will change in response, to indicate the current mode. The mode will stay active until the current line is evaluated, automatically switching back to julian (with the exception of the pkg> mode which is sticky—that is, it stays active until explicitly exited by typing backspace at the beginning of the line). The alternative modes can be exited without evaluating the expression by deleting everything on the line until the prompt changes back to julia>, or by pressing Ctrl + C.
Accessing the documentation with the help mode
The help mode provides access to documentation without having to get out of the REPL. To access it, simply type ? at the beginning of the line. You should see the help?> prompt. Now you can input text, and Julia will search the documentation for matching entries, as follows:
julia> ? help?> println search: println printstyled print_with_color print print_shortest sprint isprint println([io::IO], xs...) Print (using print) xs followed by a newline. If io is not supplied, prints to stdout. Examples ≡≡≡≡≡≡≡≡≡≡ julia> println("Hello, world") Hello, world julia> io = IOBuffer(); julia> println(io, "Hello, world") julia> String(take!(io)) "Hello, world\n"
The output supports rich formatting, via Markdown:
julia> using Profile
help?> Profile.print
Resulting a rich output as in the following screenshot:
More complex expressions can be queried, including macros, types, and variables.
For example, help?> @time:
Or help?> IO:
Shell mode
The shell mode is used to switch to a command-line interface similar to the system shell, for directly executing OS commands. To enter it, input a semicolon ; at the very beginning of the julian prompt:
julia> ;
Upon typing ; the prompt changes (in place) to shell>:
Now we can execute system-wide commands directly, without the need to wrap them in Julia code. This will list the last ten lines of your repl_history.jl file. This file is used by Julia to keep a history of the commands executed in the REPL, so your output will be different from mine:
julia> using REPL
shell> tail -n 10 ~/.julia/logs/repl_history.jl
IO
# time: 2018-09-02 21:56:47 CEST
# mode: julia
REPL.find_hist_file()
# time: 2018-09-02 21:58:47 CEST
# mode: shell
tail -n 10 ~/.julia/logs/repl_history.jl
While in REPL mode we can access Julia's API, making this a very powerful combo. For example, in order to programmatically get the path to the REPL history file, we can use the REPL.find_hist_file() function, as follows:
julia> REPL.find_hist_file() "/Users/adrian/.julia/logs/repl_history.jl"
The path to the file will be different for you.
We can use this in the shell mode by wrapping the command in $():
shell> tail -n 10 $(REPL.find_hist_file()) REPL.find_hist_file() # time: 2018-09-02 21:58:47 CEST # mode: shell tail -n 10 ~/.julia/logs/repl_history.jl # time: 2018-09-02 22:00:03 CEST # mode: shell tail -n 10 $(REPL.find_hist_file())
Similarly to the help mode, the shell mode can be exited without executing any command by pressing backspace at the beginning of the line or typing Ctrl + C.
In IJulia, the command can be executed by prefixing the input with ;, like this:
;tail -n 10 ~/.julia/logs/repl_history.jl
Search modes
Besides the help and the shell modes, there are two search modes. These are not necessarily Julia specific, being common to many *nix style editing apps.
Press the Ctrl key and the R key at the same time in order to initiate a reverse incremental search. The prompt will change to (reverse-i-search). Start typing your query and the most recent result will show. To find older results, type Ctrl + R again.
The counterpart of Ctrl + R is Ctrl + S, initiating an incremental search. The two may be used in conjunction to move through the previous or next matching results, respectively.
The startup.jl file
If you want to automatically execute some code every time you run Julia, you can add it to a special file called startup.jl. This file is not automatically created, so you'll have to add it yourself to your Julia configuration directory. Any code you add to it will be run by Julia each time it starts up. Let's have some fun and do this using Julia—and practice a bit of what we've learned so far.
First, go into shell mode and run these three commands:
shell> mkdir $(dirname(REPL.find_hist_file()))/../config shell> cd $(dirname(REPL.find_hist_file()))/../config /Users/adrian/.julia/config shell> touch startup.jl
Then, in julian mode, execute the following:
julia> write("startup.jl", "println(\"Welcome to Julia!\")") 28
What did we just do? In shell mode, we created a new directory, called config, just one folder up from where our history file was. Then we cd into the newly created folder, where we created a new file called startup.jl. Finally, we asked Julia to add the line "println(\"Welcome to Julia!\")" to the startup.jl file. Next time we start the Julia REPL we'll be greeted by this welcome message. Check this out:
REPL hooks
It is also possible to define a function that will be automatically called before starting a REPL session. To achieve this, you need to use the atreplinit(f) function, which registers a one-argument function f to be called before the REPL interface is initialized in interactive sessions. This function should be called from within the startup.jl file.
Let's say that we edit our startup.jl file so that it now looks like this:
println("Welcome to Julia!") atreplinit() do (f) println("And welcome to you too!") end
Our REPL will now greet us twice:
The atreplinit function can be used in tandem with isinteractive, which returns a Boolean true or false value that tells us whether or not Julia is running an interactive session.
Exiting the REPL
In order to exit the REPL, you can type ^ D (Ctrl + D). However, that will only work if you're at the beginning of the line (when the text buffer is empty). Otherwise just type ^C (Ctrl + C) to first interrupt (or cancel) and clear the line. You can also run exit(), which will stop the execution of the current Julia process.