Anatomy of a Julia file
Julia is a high-performance, dynamic programming language specifically designed for scientific computing and technical applications.
File extensions: .jl
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside a Julia file
Module definition
Encapsulates code and defines a namespace (module ... end).
A module block groups related definitions under a namespace, the way a package groups files. Names declared inside are qualified as MyMath.distance from the outside unless explicitly exported with export, which keeps unrelated packages from stepping on each other's sqrt or distance bindings. Modules can using or import other modules, and nesting them mirrors how Julia's own standard library is organized (Base, Core, Statistics). Unlike a Python module, a Julia module is not tied one-to-one with a file. A single file can define several, though convention keeps it to one per package entry point.
Import statement
Loads external modules (using, import).
using Statistics brings a module's exported names into scope directly, so mean(x) works unqualified. This is the common case for standard-library and package code. import Statistics instead requires qualification (Statistics.mean) unless you explicitly extend a function, which is the idiom for adding methods to someone else's generic function. Both trigger Julia's package precompilation the first time a module is loaded in a session, caching compiled code so subsequent using statements in later sessions start faster. This is also why the first call to a freshly loaded function can feel slow: t
Comment
Single-line (#) or block (#= ... =#), ignored by the compiler.
A # starts a comment that runs to the end of the line, same as Python or Ruby. Block comments are wrapped in #= and =# instead of triple quotes, and (unlike most languages' block comments) they nest, so commenting out a region that already contains a #= =# pair is safe. Julia has no dedicated docstring syntax; documentation instead uses an ordinary string literal placed immediately before a definition, which the Docs system picks up and ?functionname displays at the REPL.
Type definition (struct)
Defines a composite data type.
struct Point ... end declares an immutable composite type: once a Point is constructed its fields cannot be reassigned, which lets the compiler reason about it like a value type and often stack-allocate it. Prefixing with mutable struct opts back into reassignable fields at the cost of that optimization. Julia generates a default positional constructor automatically (Point(1.0, 2.0)) matching the field declaration order. Structs carry no methods of their own; behavior lives in standalone functions dispatched on the struct's type, which is the core of Julia's multiple-dispatch design.
Type annotation
Specifies the type of a field or argument (::Type).
The :: operator asserts a type: x::Float64 on a struct field constrains what can be stored there, while p1::Point on a function argument restricts which method applies. Annotations are optional almost everywhere (Julia infers types at compile time from whatever is actually passed) but they document intent and let multiple dispatch pick a more specific method. Omitting an annotation is not "untyped" the way a dynamically typed language usually means it; the field or argument is simply typed Any, and the compiler still specializes generated code per call site based on the concrete runtime types
Function definition (long form)
Standard multi-line function syntax.
function name(args...) ... end is the general-purpose form, used whenever a body needs more than one expression. The final evaluated expression is returned implicitly, though an explicit return (as in distance) is common for clarity or early exit. Because Julia dispatches on argument types, the same function name can have many methods (distance(p1::Point, p2::Point) coexists with, say, distance(p1::Point3D, p2::Point3D)) and Julia picks the most specific applicable method at each call site. This is multiple dispatch, and it is the feature the rest of the language's design orbits.
Function definition (short form)
Concise single-line syntax for simple functions.
area(r::Number) = pi * r^2 is sugar for a one-expression function ... end block. Mathematically minded code reads almost like the formula it implements. pi is a predefined constant of an irrational-number type that only becomes a concrete Float64 (or other precision) when it participates in an operation. This form is not a lambda; it defines a genuine named method just like the long form, participates in dispatch the same way, and can even be given additional methods later for other argument types.
String interpolation
Embeds expressions in strings using $().
A bare $name splices a variable's value into a string, and $(expression) splices the result of an arbitrary expression: "Distance: $(distance(p_a, p_b))" calls the function inline and stringifies whatever it returns. This is closer to shell or Perl interpolation than to Python's f"{...}", though it serves the same purpose. Interpolation works in both regular double-quoted strings and command backtick-strings, and a literal $ in a string must be escaped as \$ to avoid triggering it.
Control flow (loop)
Executes a block repeatedly (for, while).
for i in 1:3 iterates over a range (here, the inclusive UnitRange 1, 2, 3) or any other iterable (arrays, dicts, strings) the same way Python's for walks an iterable rather than counting indices. while repeats as long as its condition holds, and both loop forms support break and continue. Unlike a script-level for in some languages, loop bodies in Julia introduce their own scope: a variable first assigned inside the loop is not visible after end unless it was declared outside first. Ranges like 1:3 are lazy and allocation-free, so looping over even a huge range costs no more memory than loopin
Control flow (conditional)
Executes code based on a condition (if, elseif, else).
if / elseif / else branch on a Bool. Julia is strict here, so a condition must actually be true or false; there is no truthy 0 or empty-collection fallback like in Python or JavaScript. The block still ends with a single end, matching every other block construct in the language. For simple cases, the ternary cond ? a : b and short-circuiting && / || (often used for guard clauses like x < 0 && return) cover what would otherwise need a full if block.
Function call & main execution
Calling functions and running top-level code.
Julia has no single blessed "entry point" keyword; instead, if abspath(PROGRAM_FILE) == @__FILE__ checks whether the current file was launched directly rather than included or loaded as a package, mirroring Python's if __name__ == "__main__": guard. @__FILE__ is a macro (marked by @) that expands to the current file's path at parse time. Wrapping the script body in a main() function rather than leaving it at top level also helps performance: code inside a function gets specialized and compiled per argument type, while unwrapped top-level statements are executed in a more conservative, less opt
Official Julia site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.