Extra Features

Packages

There's a rapidly growing package ecosystem. See http://pkg.julialang.org


In [3]:
# "using" exports certain things from module into current namespace
# "import" does not.
using DustExtinction
import DustExtinction

In [4]:
DustExtinction.ccm89(4000., 3.1)


Out[4]:
1.4645557029425842

In [2]:
ccm89(4000.0, 3.1)


Out[2]:
1.4645557029425842

Calling compiled code

You can call external compiled code directly from Julia. The function call overhead is the same as in C.


In [7]:
# C signature:
# char *getenv(const char *name)
#
#            function library   return type  input types    input values
path = ccall((:getenv, "libc"), Ptr{Uint8}, (Ptr{Uint8},), "SHELL")
bytestring(path)


Out[7]:
"/bin/bash"

Macros ("metaprogramming")

Macros are functions operate on expressions (code) rather than values: whereas a function takes input value(s), say 3 and returns some output value, say 9, a macro takes input expression(s), say x and returns an output expression, say x^2.

One might also say that macros rewrite or generate code.

Here is an example of why we might want to do this:


In [9]:
x = rand(5)

# suppose we want to time an element-wise square
t1 = time_ns()
x.^2
t2 = time_ns()
println(t2-t1, " nanoseconds")


14037168 nanoseconds

In [10]:
@time x.^2


elapsed time: 1.2744e-5 seconds (224 bytes allocated)
Out[10]:
5-element Array{Float64,1}:
 0.0027818
 0.945088 
 0.083452 
 0.0179883
 0.90406  

In [16]:
macroexpand(:(@time x.^2))


Out[16]:
quote  # util.jl, line 53:
    local #376#b0 = Base.gc_bytes() # line 54:
    local #377#t0 = Base.time_ns() # line 55:
    local #378#g0 = Base.gc_time_ns() # line 56:
    local #379#val = x.^2 # line 57:
    local #380#g1 = Base.gc_time_ns() # line 58:
    local #381#t1 = Base.time_ns() # line 59:
    local #382#b1 = Base.gc_bytes() # line 60:
    Base.time_print(Base.-(#381#t1,#377#t0),Base.-(#382#b1,#376#b0),Base.-(#380#g1,#378#g0)) # line 61:
    #379#val
end

Macros can also be used to generate repetitive blocks of code. This is used extensively in the packages that wrap C code.

For example:


In [17]:
using FITSIO

In [18]:
# look at the source for fits_open_file
methods(fits_open_file)


Out[18]:
2 methods for generic function fits_open_file:

Wrapping up: What's the catch?

  • Julia limits slightly what you can do (but you probably won't notice).
  • Julia trades codespace (memory footprint of the code itself) for speed (a reasonable tradeoff).
  • Start-up time is not as fast as interpreted languages: Julia is not as good for very short scripts

Caveats for the user

  • Julia is a still-evolving language at version 0.3. (You may have to update parts of your code with every new release.)
  • The package ecosystem is still quite small (but growing rapidly).