Go Inspired Tour of the Julia Programming Language

I have fond memories learning Google’s programming language Go. It is the language I’ve probably been able to pick up most quickly and do something useful with. The documentation always seemed to strike a very sensible balance between giving you enough information and not going overboard with theory.

One of the things I remember liking was a web page with a tour of the language where one could try little snippets of Go code in the browser.

So I am trying to recreate the Go tour for the Julia programming language, although I am not going to make it executable here. You can get the source code here.

Hello World

Writing to the screen (standard output).

println("Hello, 世界")


Functions can take zero or more arguments. In this example, takes two parameters of type int (64 bit in this case).

As with Go, type comes after the name of the parameters. Unlike Go however Julia is not statically typed, and doesn’t require specification of type.

Note return is optional in this case, as Julia functions always returns the last evaluated expression, and everything is an expression in Julia.

function add(x::Int, y::Int)
return x + y

println(add(42, 13))


You just assign to variables, no need for a special keyword like to indicate you are creating variables.

x, y, z = 1, 2, 3
julia, python, java = true, false, "no!"

println(join([x, y, z, julia, python, java], ' '))


1 2 3 true false no!

However Julia has the keywords and to indicate scope, where you need to be explicit about it.

Here is an example illustrating their usage.

x = 10
function foo()
x = 4

global y
y = 5
return x

Say we use this function in the Julia REPL, we’ll get these results:

julia> foo()

You can see it returns 4, as expected. But if you check the value of it is still 10, because only a local was changed.

julia> x

However actually got changed because it was not a local . We explicitly said it was global.

julia> y

For Loop

For-loop is the most normal looping construct in Julia. For can iterate over collections or ranges such as .

sum = 0
for i in 0:9
sum += i


You can even specify ranges with step values such as , for every other value or negative ranges, to count backwards such as .

While Loop

It is possible to use a while loop as well even though it is less versatile.

sum = 1
while sum < 1000
sum += sum


If Statement

As with Go, we don’t use parenthesis for control structures such as for, while and if. Unlike Go there is no need to use curly brackets to indicate code blocks.

function mysqrt(x::Float64)
if x < 0
string(mysqrt(-x), "i")

println(mysqrt(2.0), " ", mysqrt(-4.0))



Julia is similar to Go in that there is no implementation inheritance and it uses simple structs to define composite types.

struct FooBar

You don’t have to specify type information but, when you do that makes it possible to lay out instances of in memory the same way as in C or Go.

a = FooBar('B', 12, "Days")

The fields can be accessed in various ways. Normal way:

julia> a.spam
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)

By providing a symbol object, equal to the name of the field:

julia> getfield(a, :foo)

Giving an index to the field:

julia> getfield(a, 3)


A dictionary maps keys to values.

struct Vertex

m = Dict{String, Vertex}()
m["Bell Labs"] = Vertex(40.68433, -74.39967)
println(m["Bell Labs"])

We can initialize the dictionary directly with its keys and values as well.

m = Dict("Bell Labs" => Vertex(40.68433, -74.39967))


Unlike Go, but like most languages the length is not part of normal Julia arrays. is one dimensional array of integers. Below Julia deduces the type of the array elements:

p = [2, 3, 5, 7, 11, 13]
println("p == ", p)
for i = 1:length(p)
print("p[$i] == $(p[i])\n")

You can specify that elements should be of specific types, however. This makes an array, where each element is an 8-bit unsigned integer.

p = UInt8[2, 3, 5, 7, 11, 13]

Julia being aimed at numerical computing, has been built with multidimensional arrays from the start, so you can create e.g. matrices easily.

julia> m = [1 2 3; 3 4 5]
2×3 Array{Int64,2}:
1 2 3
3 4 5


You can easily pull out sub sections of an array, called slices in Julia, just like in Go.

a = [2, 4, 6, 8, 10]

However it is a more generic thing in Julia a not built into the language. Rather it relies on the fact that you can pass any object to the index operator in Julia, and it will simply invoke the appropriate function.

  • will invoke the function.
  • will invoke , because creates a unit range object.

This extents to anything so you could also pass other arrays as an argument to the index operator:

julia> a[[3,2]]
2-element Array{Int64,1}:

Which causes Julia to treat each element in the array as an index into the array.

Function Values

Functions are values too. They can be passed around just like other values.

Function values may be used as function arguments and return values.

hypot = (x, y) -> sqrt(x^2 + y^2)
println(hypot(3, 4))

Function Closures

Julia functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is “bound” to the variables.

For example, the adder function returns a closure. Each closure is bound to its own sum variable.

function adder()
sum = 0
x -> sum += x

pos, neg = adder(), adder()
for i = 0:9
println(pos(i), " ", neg(-2*i))

Compared to the Go example you can see that we don’t have to explicitly return values, when defining functions and closures. Go needs to because it distinguishes between expressions and statements.


Neither Julia nor Go is really object oriented languages, however Go does have method in the sense that you can associate functions with particular types.

Julia however does not have methods in the traditional OOP sense. Methods in OOP means you pick a particular function implementation based on the first argument to a function, the this pointer. Normally this argument is not explicitly stated in OOP languages except in Go and Python.

Julia however will pick which method to execute at runtime based on the type of all the arguments of the function. So in the example below, we got one function with two methods:

  • One operating on verticies
  • The other on floating point numbers.
struct Vertex

function abs(v::Vertex)
sqrt(v.x^2 + v.y^2)

function abs(f::Float64)
f < 0 ? -f : f

v = Vertex(3, 4)

v = -sqrt(2)


Go comes with quite a lot of functionality built directly into the language, such as dictionaries and arrays. Julia is quite the opposite, dictionaries and arrays are supplied as library functionality. Even numbers which are normally built into a language, are defined by libraries in Julia. So you can in principle define your own number types.

This goes for things like enums as well. They are not built into the language, but in the Julia standard library we have macros which allow you to create enums. All macros start with a .

@enum Weekday monday tuesday wednesday thursday friday

function describe(day::Weekday)
if day == monday
"Moon day"
elseif day == tuesday
"Tyr's day"


What the macro does is really just defining a type in this case with concrete instances named , etc. It also defined functions so that will return a sensible string for a given enum.

Where to Go From Here

I’ve only scratched the surface of Julia in this tour. It is not really that the language is very complicated, but it has a very powerful core, which allows you to create a lot of powerful constructs.

If you want to learn more, you can head over to the official Julia website. Or check out some of my videos:

Written by

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store