# Julia Programming

## Writing Functions

Julia functions can be written as one-liners. For example, the core of the Mux.jl middleware library consists entirely of one-liners:

mux(f) = f
mux(m, f) = x -> m(f, x)
mux(ms...) = foldr(mux, ms)

stack(m) = m
stack(m, n) = (f, x) -> m(mux(n, f), x)
stack(ms...) = foldl(stack, ms)

branch(p, t) = (f, x) -> (p(x) ? t : f)(x)
branch(p, t...) = branch(p, mux(t...))

(Source)

For multi-line functions, I prefer using begin blocks rather than function blocks:

# Good: Function definition via assignment
trapezoid_rule(fn, a, b, n) = begin
delta = (b - a) / n
nodes = (a + delta * k for k in 0:n)
weights = (delta * (k == 0 || k == n ? 0.5 : 1) for k in 0:n)
sum(fn(node) * weight for (node, weight) in zip(nodes, weights))
end

# Less Good: Using the "function" keyword
function trapezoid_rule(fn, a, b, n)
# insert code here
end

This is just a personal style preference, and an unusual one at that. My rationale is as follows:

1. The function keyword is uneccesarrily large (fn or def would have been sufficed).
2. Assignment expressions are how one-line functions are defined. So using them for multi-line functions adds some consistency.

## Compilation

Julia is not an interpreted languages. Rather, functions are compiled directly into native machine code. Consider the following function:

f(x) = x * x

Calling the @code_native macro on an evaluation of this function will show the native code:

julia> @code_native f(3)
.text
imulq   %rdi, %rdi
movq    %rdi, %rax
retq
nopl    (%rax,%rax)

(Comments removed. Your results might differ). Notice that the generated code differs based on the argument type(s):

julia> @code_native f(3.0)
.text
vmulsd  %xmm0, %xmm0, %xmm0
retq
nopw    %cs:(%rax,%rax)

LLVM is used as the compilation backend. Use the @code_native to see the LLVM bytecode generated by the compiler frontend.

# Linux Files

A file is an interface for accessing system resources. Most familiarly, they can be used to access data stored on disk. But they have other uses as well:

• Share RAM-backed data across processes via shared memory files.
• Enable processes to "talk" to each other via named pipes and socket files.
• On GNU/Linux: Inspect the contents of a running program's memory via the /proc/{PID}/mem file.
On GNU/Linux systems, file i/o is provided by the libc library. Check out the libc manual for authoritative information. This guide will cover some of the functionality presented in chapters 11 through 16. Code examples are given in Julia (via the ccall function to interface with libc).