Creation date: 2020-07-01
This is part 2 of an ongoing series about Julia. If you missed part 1:
In this post I want show you how to use the REPL (Read-eval-print loop) and to use Revise.jl which in my opinion is THE extension everyone should use!
If you enjoy the video format more than reading a blog: First of all: Thanks that you're here and not on YouTube/Netflix/Twitch etc :D You might wanna have a look at this wonderful video about the REPL: Julia REPL tips and tricks by BrainRPG.
That are well spent 40 minutes ;) Anyway as you're here let's continue.
After downloading/installing the latest version (now 1.4.2) you can just type
julia in your REPL and get greeted like this:
> julia _ _ _ _(_)_ | Documentation: https://docs.julialang.org (_) | (_) (_) | _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 1.4.2 (2020-05-23) _/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release |__/ | julia>
You get some useful information right there which newcomers often miss as they are too excited to try it out. Maybe you've been there and are now reading this post to get some more tips & tricks.
I'm talking about the different REPL modes:
? for help mode
; for shell mode
] for package mode
You can simply type one of those characters to switch to the mode.
? you see:
You can get help about functions like getting their docstring using this method.
In the last post I talked about
methods to see which methods are implemented for a given function.
help?> methods search: methods methodswith Method MethodError hasmethod methods(f, [types], [module]) Return the method table for f. If types is specified, return an array of methods whose types match. If module is specified, return an array of methods defined in that module. A list of modules can also be specified as an array. │ Julia 1.4 │ │ At least Julia 1.4 is required for specifying a module.
The first line shows you a list of functions with a similar name which might be handy if you mistyped the function name.
Or if you just have a typo:
help?> metods search: methods methodswith Method MethodError hasmethod
This way you also sometimes learn new useful functions.
You have no clue what the method is called? I guess you still now what you want to do with it ;)
Maybe have a look at
julia> apropos("standard deviation") Base.randn Random.randn! Statistics.stdm Statistics.std
You're probably looking for
Statistics.std. I have to admit that often this way you get quite a long list of possibilities but it can be a reasonable method if you don't have an internet connection.
In the end of this post I have a list of resources you might want to check out when learning Julia :)
The next mode in our list is the shell mode which you can enter with
I don't actually know how well this works on Windows but it's quite useful on Linux and probably Mac.
You can just use your normal commands that you use in your shell like
pwd and so on. These are only the ones I use frequently. Depending on your workflow you might wanna use
git with that as well.
It is often nice to be able to do a quick command in the same directory instead of opening a new terminal for it.
That said you can use Julia itself for some of those commands as well:
help?> cd search: cd Cdouble gcd gcdx secd asecd cld Cmd codeunit codeunits codepoint code_llvm code_typed code_native code_lowered code_warntype @cmd ncodeunits @code_llvm @code_typed @code_native @code_lowered cd(dir::AbstractString=homedir()) Set the current working directory.
Let's get to the last REPL mode before discussing
Revise a bit.
You can add packages with this mode as well as updating/removing them. Follow me with
This mode is a little special as you see the package environment we are in. At the moment we are in the global environment. If you need different package versions in different projects/environments, you can create a new environment by using
(@v1.4) pkg> ?activate activate activate [--shared] path Activate the environment at the given path, or the home project environment if no path is specified. The active environment is the environment that is modified by executing package commands. When the option --shared is given, path will be assumed to be a directory name and searched for in the environments folders of the depots in the depot stack. In case no such environment exists in any of the depots, it will be placed in the first depot of the stack.
i.e if I want to add a dependency to my ConstraintSolver I would write
] (@v1.4) pkg> activate /home/ole/Julia/ConstraintSolver Activating environment at `~/Julia/ConstraintSolver/Project.toml` (ConstraintSolver) pkg>
but that might be needed in your first steps so don't worry about that now :)
Instead let's install Revise.jl as I mentioned it's THE package you need. If you don't trust me, you might click on the link to check it out before you follow the installation.
(ConstraintSolver) pkg> activate Activating environment at `~/.julia/environments/v1.4/Project.toml`
<- Just to get back to the general environment for me. You probably don't have the ConstraintSolver so you don't need it.
(@v1.4) pkg> add Revise Updating registry at `~/.julia/registries/General` Updating git-repo `https://github.com/JuliaRegistries/General.git` Resolving package versions... Updating `~/.julia/environments/v1.4/Project.toml` [295af30f] + Revise v2.7.3 Updating `~/.julia/environments/v1.4/Manifest.toml` [no changes]
And now v2.7.3 of Revise is installed. Simple, isn't it?
Before I jump into Revise let's stay in this REPL mode for a bit if you don't mind.
Checking which packages one has installed in the current environment:
(@v1.4) pkg> status Status `~/.julia/environments/v1.4/Project.toml` [c7e460c6] ArgParse v1.1.0 [c52e3926] Atom v0.12.15 [67c07d97] Automa v0.8.0 [6e4b80f9] BenchmarkTools v0.5.0 [00ebfdb7] CSTParser v2.4.0 ... [1986cc42] Unitful v1.1.0 [`~/.julia/dev/Unitful`] [44d3d7a6] Weave v0.9.4 [ade2ca70] Dates [8bb1440f] DelimitedFiles [3fa0cd96] REPL
I don't wanna fill your screen ... I have quite a lot installed and can probably uninstall some of them. You can see the version number for each package here (besides standard libraries like Dates). For
Unitful you can see that I have checked it out for development. (Just some test I think).
If you want to improve Revise (or any other package) you can use
(@v1.4) pkg> dev Revise
and then the repo will be cloned to
~/.julia/dev/Revise and you can implement your awesome feature.
Okay let's check whether there are some updates:
(@v1.4) pkg> up Updating registry at `~/.julia/registries/General` Updating git-repo `https://github.com/JuliaRegistries/General.git` Updating git-repo `https://github.com/wookay/TwitchTools.jl` Installed Adapt ───────────────────── v2.0.2 Installed Images ──────────────────── v0.22.4 Installed HTTP ────────────────────── v0.8.16 Installed Plots ───────────────────── v1.5.1 Installed Pluto ───────────────────── v0.9.11 Installed PackageCompiler ─────────── v1.2.0 Installed Colors ──────────────────── v0.12.3 ... Updating `~/.julia/environments/v1.4/Project.toml` [5ae59095] ↑ Colors v0.12.2 ⇒ v0.12.3 [713c75ef] ↑ Franklin v0.8.5 ⇒ v0.8.6 [cd3eb016] ↑ HTTP v0.8.15 ⇒ v0.8.16 [916415d5] ↑ Images v0.22.3 ⇒ v0.22.4 [9b87118b] ↑ PackageCompiler v1.1.1 ⇒ v1.2.0 [91a5bcdd] ↑ Plots v1.4.3 ⇒ v1.5.1 [c3e4b0f8] ↑ Pluto v0.9.10 ⇒ v0.9.11 Updating `~/.julia/environments/v1.4/Manifest.toml` [79e6a3ab] + Adapt v2.0.2 [3da002f7] ↑ ColorTypes v0.10.4 ⇒ v0.10.5 [5ae59095] ↑ Colors v0.12.2 ⇒ v0.12.3 ...
okay maybe I haven't done this for a bit but some packages get frequently updated ;)
Maybe it's a good moment to talk a bit about
Manifest.toml without getting too deep. Each environment has both of these files.
defines the direct dependencies and some bounds
defines all dependencies exactly
Let me give you an example:
For my ConstraintSolver (which btw you really should check out!)
name = "ConstraintSolver" uuid = "e0e52ebd-5523-408d-9ca3-7641f1cd1405" authors = ["Ole Kröger <email@example.com>"] version = "0.2.2" [deps] Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" MatrixNetworks = "4f449596-a032-5618-b826-5a251cb6dc11" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [compat] Formatting = "^0.4.1" JSON = "~0.18, ~0.19, ~0.20, ~0.21" JuMP = "^0.21.3" MathOptInterface = "^0.9.11" MatrixNetworks = "^1" julia = "1" [extras] Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["ForwardDiff", "LinearAlgebra", "Test", "JSON", "Cbc", "GLPK", "Combinatorics", "Random"]
The first block gives the name and version of the package. Then
[deps] is a list of dependencies with their
uuid. In this example my ConstraintSolver needs these 6 packages to function.
[compat] describes which versions I need for each of these packages. The symbols like
^ are best described in the docs.
[targets] describe some packages I need for my test cases but are not required to use my solver.
Okay let's have a look at
... [[Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[MathOptInterface]] deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"] git-tree-sha1 = "cd2049c055c7d192a235670d50faa375361624ba" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" version = "0.9.14" ...
There all packages are defined which are dependencies of dependencies. It also defines exactly which version I used for testing it locally. This can be useful if you have a problem with a package and file a bug report. If you used the latest version of MathOptInterface and I thought it works (with my compat bounds) I can see that you used a different version than I do and can fix the compat bounds/file an issue at MathOptInterface or fix my solver such that it works.
Okay now you really want to know how to remove a package, right?
(@v1.4) pkg> rm Unitful Updating `~/.julia/environments/v1.4/Project.toml` [1986cc42] - Unitful v1.1.0 [`~/.julia/dev/Unitful`] Updating `~/.julia/environments/v1.4/Manifest.toml` [no changes]
Is there something else I wanted to mention?
A yeah you might want to install a special version of one package or a specific branch. The help mode ... helps ;)
(@v1.4) pkg> ?add add [--preserve=
] pkg[=uuid] [@version] [#rev] ... Examples pkg> add Example pkg> add --preserve=all Example pkg> add Example@0.5 pkg> add Example#master pkg> add Example#c37b675
Okay now let's really check out this package.
After you played around in your REPL for a while you might want to start your first project or just open a file and write some functions.
How about learning some code with Project Euler
The problem we try to solve:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
I don't like to write functions in the REPL, so I open a file:
function sum_mul35_below(below=1000) end
Did I mention that I'm bad at naming functions especially for Project Euler problems?
Okay you might start with:
function sum_mul35_below(below=1000) sum = 0 for i=1:below-1 if i % 3 == 0 sum += i end if i % 5 == 0 sum += i end end return sum end
You can of course copy it into your REPL and evaluate it but I think including the file is much easier.
You run it with
sum_mul35_below(16) to get
75 and maybe you think that's seems high and check:
3+5+6+9+10+12+15 is 60. Then you realize you've added 15 twice by jumping into both ifs and change your code to:
function sum_mul35_below(below=1000) sum = 0 for i=1:below-1 if i % 3 == 0 || i % 5 == 0 sum += i end end return sum end
julia> sum_mul35_below(16) 75
julia> sum_mul35_below(16) 60
This might seem a bit tedious. Wouldn't it be nice if you don't have to type
include again and again and again?
Guess what: Revise is there for rescue.
] add Revise using Revise includet("euler_1.jl")
Don't forget the
So yeah I missed that in the package mode section as it's outside that mode: You use a package with
It also works when you develop a package where it is even more useful. For example
using Revise using ConstraintSolver
doing some changes in ConstraintSolver and you can just test them in the REPL.
That's the reason why I think everyone should use that package ;)
A small note: The above code is not the fastest. Feel free to check out my Project Euler streams on Twitch or YouTube. I'm currently at problem 23 and stream for about 2 hours every Wednesday at 3PM UTC.
Would love to see you there as I might need some help with more complicated problems ;)
For questions which should remain for a longer period
For longer questions not suited for Chat based systems
The link brings you to the registration page
Awesome for short questions to get answers very fast
Chat based so sometimes your question gets overlooked if there are other question directly after yours
Introduce yourself in #introduction and questions go to #helpdesk
There are some more useful channels if you are interested in special topics
Similar to Slack but questions don't get overlooked based on their threaded system
Fewer people than in Slack
There is of course also StackOverflow but not much is going on there. Maybe I'm not the only one who thinks it's a toxic environment especially for newcomers...
There is a lot more to cover but this should be a good start for the basics in my opinion. On my list of posts in this series are things like:
Useful macros without getting into detail on how they work
Packages with less than 100 stars which I find awesome
Debugger vs Infiltrator
If you're a beginner you might be interested in: Getting mentored
Thanks for reading and special thanks to my eight patrons!
List of patrons paying more than 4$ per month:
Currently I get 24$ per Month using Patreon and PayPal.
For a donation of a single dollar per month you get early access to the posts. Try it out at the start of a month and if you don't enjoy it just cancel your subscription before pay day (end of month).