Functions in Julia
As promised in the last article of last week, we’ll be taking a proper look at functions in Julia. And what is that exclamation mark anyway? What metaphors are appropriate for Julian functions? We’ll answer all these questions shortly
Definition
Functions are defined using the function
keyword, as usual terminated with the keyword end
as usual, making indentation superfluous
julia> function hi(name)
print(name)
end
hi (generic function with 1 method)
You can also define short functions one line
julia> hey(name)= print(name)
hey (generic function with 1 method)
And this is precisely where having LaTeX symbols in our lexicon completely distinguishes Julia. As we can name our functions so as to facilitate understanding while also keeping brevity. Done correctly, we can get our (Pluto) notebooks to read quite like math notes!
julia> Π(x::Array{Int64}) = prod(x)
Π (generic function with 1 method)
julia> factorial(n::Int) = Π(collect(1:n))
factorial (generic function with 1 methods)
julia> factorial(2)
2
julia> factorial(3)
6
As is common, you can explicitly return a value, in which case the function stops there, or you can let the last expression be returned implicitly, as done in above functions:
julia> explicitReturn(x)=(factorial(x); return "Ha!"; print("I never show"))
explicitReturn (generic function with 1 method)
julia> explicitReturn(123)
"Ha!"
Oh, and what about those functions with an exclamation mark ? Well, that’s just a naming convention that I humbly ask you to follow when defining your own functions. Its simple, whenever your function mutates i.e. changes it’s input arguments, you should end that function’s name with !
.
Typing
We can force a particular return type on a function just like we assert a DataType on a variable. If you want to read more about all that, you should read our full article on DataTypes here. But for now, just note that we use the ::
operator to assert the type of a variable, and that functions are first-class objects in Julia:
julia> typedReturn(x)::Int=(factorial(x); return "Ha!"; print("I never show"))
typedReturn (generic function with 1 method)
Be careful, the above function, though defined, will never successfully execute, as it returns a string while expecting an integer!
Now, if you want a function to actually return nothing whatsoever, you’ll have to explicitly return nothing
julia> Nothing() = return nothing
Nothing
julia> Nothing() #Note the lack of output below
But what if you like gifting, and would like to return a lot of stuff? Well, you’d bundle it up in a tuple:
julia> gifter(x,y,z)=return (x,y,z)
gifter (generic function with 1 method)
julia> gifter("machine","learning","geek")
("machine", "learning", "geek")
And then you unpack the gifts at once, and give it a fancy name ‘destructuring’
julia> M,L,G=gifter("machine","learning","geek"); print("M:$M |L:$L |G:$G ")
M:machine |L:learning |G:geek
What if you instead want to pass on a variable number of arguments? You simply add an ellipsis to the last argument, and iterate over it to get each argument( in order):
julia> function reciever(gifts...)
[print("$gift and ") for gift ∈ gifts]
return nothing
end
reciever (generic function with 1 method)
julia> reciever("Hi",1,"hello",(1,2,3))
Hi and 1 and hello and (1, 2, 3) and
return nothing end reciever (generic function with 1 method) julia> reciever(“Hi”,1,”hello”,(1,2,3)) Hi and 1 and hello and (1, 2, 3) and
Anonymous/Lambda functions
We can define functions without a name via two syntaxes. Either we can simply skip the name part in a normal definition:
julia> function(x)
x^2
end
#1 (generic function with 1 method)
julia> ans(10)
100
Or you can use the ->
token:
julia> x->x^2
#2 (generic function with 1 method)
julia> ans(100)
10000
Canonically, we’d use them in functions like map
julia> map(x->x^2,collect(1:10))
10-element Array{Int64,1}:
1
4
9
16
25
36
49
64
81
100
And that’s a wrap folks. We’re almost done with this mini-series on Julia. Next up we’ll be looking at exception handling and databases.