
You'll discover the real reason Julia was created: the two-language problem, where scientists were forced to prototype in Python or R and then rewrite the slow parts in C or Fortran. You will see how the founders' 2012 manifesto - speed of C, dynamism of Ruby, math syntax of MATLAB, generality of Python, statistics of R - maps directly onto the language features you will use for the rest of the course.
You'll write and run your very first Julia program using println and print, and watch exactly how the trailing newline changes what shows up in your console. Along the way, as you stack lines into a stat sheet and assemble a one-line banner piece by piece, you will get comfortable with the core loop: type an expression, run it, and read back the output.
You'll learn Julia's string interpolation, splicing variables and even full arithmetic expressions straight into a string with the $(...) syntax. You will also meet string(...) and repr(...) as alternatives and see how interpolation compares to Python f-strings, so the substitution mechanics become second nature while you assemble a character's status card.
You'll learn how to document Julia code with single-line # comments, multi-line #= ... =# block comments, and triple-quoted docstrings attached to your functions and types. You will then pull a docstring back up through the help system with @doc, seeing first-hand that documentation in Julia is a first-class feature that powers both inline help and generated docs.
You'll master the four REPL modes you will reach for every day: Julian for code, help mode (?) for documentation, shell mode (;) for OS commands, and Pkg mode (]) for packages. By switching between them in a single short session you will build the muscle memory that keeps you from ever leaving the prompt for routine work.
You'll follow Julia's journey on a clear timeline - from the 2012 public release, through the milestone 1.0 in 2018 and the long-term-support line, to today's mature versions. You will see the organizational landmarks too, including JuliaCon and the community behind it, and walk through real production users - the Federal Reserve story among them - leaving you with a real sense of Julia as a production platform rather than an experiment.
You'll assign variables in Julia and understand that names are bindings to values, not fixed typed containers - so you can rebind a name to a different type and watch it work. You will also use Julia's standout feature: Unicode variable names like the Greek letter alpha, entered with LaTeX-style tab completion right in the REPL, and reach for the built-in pi constant in a quick calculation.
You'll work hands-on with Julia's primitive types - Int64, Float64, Bool, and Char - and use typeof to inspect each one. You will see why integer width is platform-dependent but can be pinned down (Int32, UInt8, Int128), why Float64 is the IEEE-754 standard, and why a Char is a full 32-bit Unicode code point - able to hold an emoji - rather than a single byte.
You'll handle strings as immutable sequences of Unicode characters: indexing into a hero name, concatenating with * rather than + (a deliberate Julia choice that catches Python developers off guard), and watching the + concatenation trap fail. You will also learn why byte indices and character indices differ for non-ASCII text, using a multi-byte example to see sizeof and length disagree.
You'll add optional type annotations with the :: operator, trigger and read a type-assertion failure, and walk up the numeric tower with supertype - from Int64 through Signed, Integer, Real, Number, all the way to Any. Tracing that real path through the hierarchy gives you the foundation that multiple dispatch will build on later.
You'll run a growing factorial-style product loop and watch a fixed-width Int silently overflow once the numbers cross the ceiling, then re-seed the same algorithm with BigInt to get the correct astronomical answer. You will also use BigFloat with setprecision to push a value like the golden ratio to as many digits as you like, seeing why arbitrary-precision arithmetic being built in - not bolted on - is a big reason Julia is trusted in scientific computing.
You'll get to the conceptual heart of Julia: multiple dispatch as the main way behavior is organized. You will see how it differs from single-dispatch object orientation in Java or Python and from the free functions of C, and why this middle path lets independently written packages compose without glue code - the famous Julia ecosystem effect.
You'll exercise Julia's full arithmetic toolkit - +, -, *, /, integer division, modulo %, and exponentiation ^ - and then use the math-style syntax Julia got right, writing a number next to a variable like 2x as valid multiplication. Seeing this natural notation actually run shows why Julia feels so at home for anyone with a math or science background.
You'll use comparison operators and boolean logic, and write chained comparisons like 0 < x < 100 that read exactly as they do in mathematics and short-circuit correctly. You will also learn the idiomatic trick of using && and || as control flow on their own, and how they differ from the bitwise & and |.
You'll branch your code with if / elseif / else / end to classify a value, then write the same logic compactly with the ternary cond ? a : b operator. You will also discover that if is itself an expression that returns a value in Julia, so you can bind the result of a branch - such as a rank chosen from an XP score - directly to a variable.
You'll iterate with for loops over ranges like 1:5, change the step with 1:2:10, and loop over arrays with the exact same syntax. You will also learn that ranges are lazy - 1:1_000_000_000 allocates nothing - introducing a laziness pattern you will keep meeting throughout Julia.
You'll write while loops and control them with break and continue, building a search that skips certain values and stops the moment it finds its answer, printing the loop's state as it runs. You will also see why Julia uses the end keyword to close blocks instead of indentation or braces - one of the most recognizable features of Julia source.
You'll get an honest, balanced look at where Julia hurts: the time-to-first-plot delay and the precompilation work softening it, the smaller package ecosystem next to Python, the learning curve around type stability and method ambiguities, and the thin mobile and frontend story. Each weakness is paired with the community's mitigation, so you leave trusting the course not to whitewash the rough edges.
You'll define functions both ways Julia offers - the long function ... end form and the compact one-line f(x) = ... form - and confirm they behave identically. You will also see that Julia returns the value of the last expression by default, making the explicit return keyword optional - except when you reach for it deliberately to exit a function early.
You'll learn how Julia separates positional arguments from keyword arguments with the semicolon in a signature, and how to attach default values to either kind. You will define a function with positional, defaulted, and keyword arguments, then call it several ways to see how readable and flexible the call sites become, with a quick side-by-side against Python's signature line.
You'll write anonymous functions with the arrow syntax x -> x^2, pass one into map, and then refactor that same call into Julia's elegant do block form. You will come away understanding that a do block is not special syntax at all - it is just sugar for passing an anonymous function as the first argument, a pattern used everywhere from file IO to threading.
You'll make multiple dispatch concrete by writing several methods of one function - each specialized on Int, Float64, and String - and watching Julia pick the right one for each call. Using methods() to list them all, and finishing with a method that dispatches on two arguments at once, you will start reading any Julia function as a collection of methods distinguished by their argument types.
You'll extend the + operator to your own type by defining a Money struct and adding a method to Base.+ that adds two amounts while refusing to mix currencies. This reveals a quietly profound design choice: Julia has no magic or dunder methods because every operator is already an ordinary function open to dispatch, so even sum just works on a list of your own values.
You'll see the technical specs behind Julia's speed: an LLVM-based JIT compiler, type inference that emits specialized native code per call signature, garbage collection, optional typing, and built-in numerics. You will examine the famous microbenchmarks against C, Fortran, Python, R, and MATLAB - what they prove and what they don't - plus the real-world Celeste astronomy headline.
You'll work with one-dimensional arrays, Julia's most common collection: creating one, indexing it (remembering Julia counts from 1), and mutating it with push! and pop! while watching each change. You will also learn that the trailing ! marking mutating functions is just a naming convention, and that arrays underpin Julia's entire numerical ecosystem.
You'll build a 3x3 matrix with Julia's space-and-semicolon literal syntax and run element-wise operations using dot broadcasting, like A .+ 5 and sqrt.(A). You will learn that the dot is a compiler-level fusion mechanism, so a chain of broadcast calls collapses into a single loop with no temporary arrays - one of Julia's most distinctive performance features.
You'll use tuples as immutable, fixed-length, mixed-type collections, destructuring one into variables and seeing the error when you try to change an entry. You will then build a named tuple with field-style access and learn why named tuples have become Julia's zero-overhead, recommended way to return multiple values from a function.
You'll build a Dict mapping strings to integers, insert and update entries, loop over key-value pairs, and check membership with haskey. You will then create a Set and run union and intersect, while noticing how Julia infers the element types straight from your literals.
You'll build collections declaratively with array, generator, and dictionary comprehensions - squares, paired combinations from a nested comprehension, and a dictionary over a range - and add an if filter clause to keep only what you want. By comparing a fully materialized comprehension with its lazy generator twin, you will start reaching for comprehensions instead of explicit loops.
You'll get a one-glance map of the modern Julia ecosystem: the four pillars that hold it together, the package manager Pkg with reproducible environments, the flagship libraries grouped by what they do, and the GitHub organizations behind them. You will also see who actually ships Julia in production and get a clear read on when to reach for Julia versus Python.
You'll design your own type hierarchy: an abstract Shape type with concrete Circle and Rectangle structs, plus an area method per type that you call polymorphically through a vector of shapes - then extend the family with a Triangle and watch it slot right in. You will learn that Julia uses abstract types as dispatch hooks and statements of intent, not as field inheritance - a distinction that matters because Julia has no classical inheritance.
You'll write a parametric struct with a single type parameter {T}, build concrete instances over different element types, and add an unwrap method that reads the type parameter back out with the where syntax. You will also constrain a parameter to a supertype like Number, and see how parametric types give Julia zero-cost generics: each concrete instantiation compiles to its own specialized native code, with no boxing or virtual-call overhead.
You'll define an immutable Point struct and a mutable Counter struct, construct each, and trigger the error you get from trying to change an immutable field. You will then redefine Counter with the @kwdef macro to gain keyword-based defaults, learning when to pick mutable versus immutable and how macros extend the syntax at no runtime cost.
You'll compose declarative pipelines with map, filter, and reduce - squaring elements, keeping the even ones, and summing the result - then rewrite the same computation as a single broadcast-and-fold chain using foldl. You will also meet mapreduce as a fused, one-pass variant, so you can favor pipelines over imperative loops when the problem fits.
You'll create a generator expression with parentheses and confirm that nothing is materialized until you consume it, piping it through sum for lazy aggregation and collect for eager realization. You will then define a custom iterator by extending Base.iterate and drive it with a for loop, building the lazy-iteration mindset needed for huge or infinite streams.
You'll trace Julia's compilation pipeline from start to finish: parsing to a surface AST, lowering to typed IR, type inference across method calls, optimization, LLVM IR, and finally native code. You will see how @code_warntype, @code_typed, @code_llvm, and @code_native let you inspect each stage, and why this JIT-specialization design is what lets Julia hit C speed without losing dynamism.
You'll spawn concurrent work with @async, run two tasks that report progress after a short sleep, and wait for both to finish. You will then use a Channel to pass values from a producer task to a consumer, and wire up a channel-powered battle log, learning how Julia's real coroutines differ from Python's asyncio.
You'll parallelize a loop across CPU cores with Threads.@threads, summing squares into a per-thread buffer to avoid a data race, and check Threads.nthreads() to confirm how many threads ran. You will also meet Atomic{Int} for safely sharing a counter and ReentrantLock for more complex shared state, seeing that threading is built into the language - but correctness is still on you.
You'll add worker processes with addprocs and run a @distributed reduction across them to compute a parallel sum, confirming the worker count with nworkers(). You will use @everywhere to make a function available on every worker, completing your parallelism toolkit: async tasks for IO, threads for shared memory, and distributed processes for multi-node scale.
You'll wrap a risky operation in try / catch / finally, print the type and message of the caught exception, and guarantee a cleanup line always runs. You will then define a custom exception type with its own fields, throw it, and catch it with a type-specific clause - learning the idiom of reserving exceptions for truly exceptional cases while using value-returning helpers like tryparse for expected failures.
You'll manage resources the idiomatic way with the open(...) do io ... end form - Julia's answer to Python's with - opening a file, writing to it, and letting the do block close it automatically before you read the content back. You will also use the do-block form to take a lock safely and even build your own do-block API, seeing once more that Julia expresses features through composition rather than dedicated syntax.
You'll write your first macro, @sayhello, using macro ... end and quote ... end so it expands into a println call at parse time, then inspect the expansion with @macroexpand before it runs. You will also meet everyday built-in macros like @time, @show, and @assert, build your own @celebrate wrapper, and understand that they are just regular code running at compile time - the same power that underwrites Julia's biggest libraries.
You'll learn type stability - the single most important performance concept in Julia - by comparing a type-stable function whose return type is fixed by its argument types against an unstable one whose return type depends on runtime values. You will see exactly what the optimizer does in each case and why most Julia performance problems trace back to a type-unstable function hiding somewhere.
You'll build a mental model of Julia's memory: the stack for isolated bits-types, the heap for mutable and abstractly-typed objects, and the generational tracing garbage collector. You will learn why unnecessary allocations hurt hot loops, the detection toolkit for measuring them, and the techniques that cut GC pressure - pre-allocated buffers, views, and the array-of-structs versus struct-of-arrays tradeoff.
You'll picture a generic function's method table as a registry of signatures indexed by argument-type tuples, and walk through dispatch resolution step by step: gathering applicable methods, sorting by specificity, detecting ambiguities, and choosing the most specific match. You will also learn about invalidation - what happens when a new method is added to already-compiled code - and why it affects compile latency.
You'll learn the design patterns that make Julia code look truly native rather than translated from Python or C: Holy traits for emulating multiple inheritance, parametric structs for type-stable containers, the do-block-for-resources idiom, the @kwdef shortcut for default fields, and duck typing through multiple dispatch. With these recognizable shapes in hand, intermediate Julia source stops looking exotic.
You'll map out the domains where Julia genuinely wins, with the libraries that power them: differential equations and scientific ML via SciML, optimization and operations research via JuMP, probabilistic programming via Turing, GPU computing, and automatic differentiation in its two main flavors. You will leave with a realistic map of when Julia is the right tool and when another language wins.
This course contains the use of artificial intelligence.
Scientific computing has lived under a quiet tax for decades: prototype in a high-level language, then rewrite the hot paths in C or Fortran. Julia was designed to end that compromise. It gives you the readability of Python, the speed of compiled code, and a type system built around multiple dispatch - a design choice that quietly reshapes how you structure programs. As machine learning, computational finance, climate modeling, and differential equation research push against the limits of slower languages, Julia has moved from an MIT experiment to a serious production tool at companies and labs that cannot afford to choose between expressiveness and performance.
This course takes you from your first println to writing concurrent, generic, type-stable Julia code, and it does it by weaving concept and practice together across seven sections. Every coding section opens with a short context lecture - the origin story, the design philosophy, the honest tradeoffs, the speed claim and its asterisks - so you understand why a feature exists before you write it. Then you get straight into hands-on code: variables and the numeric tower, strings, operators and control flow, functions and multiple dispatch, collections and broadcasting, parametric types and generics, higher-order functions and lazy iterators, concurrency with tasks and channels, multi-threading, distributed computing, error handling, and a first serious look at macros and metaprogramming. To keep the practice memorable, the runnable examples are built around a light game-and-adventure theme - heroes, bosses, loot, and spell damage - so the syntax sticks while the concepts stay rigorous.
The course then closes, in its final section, with a deeper run of conceptual lectures that open the hood completely: type stability and what the optimizer does with it, memory and the garbage collector, method tables and dispatch resolution, the idioms that mark real Julia code, and a final map of the domains where Julia genuinely wins.
This course is for programmers who already know at least one language and want a rigorous, honest introduction to Julia - including where it hurts. You should be comfortable with basic programming concepts like variables, loops, and functions, and willing to install Julia locally and use a terminal. By the end you will be able to read idiomatic Julia, design programs around multiple dispatch, write code the compiler can specialize, parallelize work across threads and processes, and reason about performance instead of guessing at it.
What sets this course apart is that it refuses to sell Julia as magic. You will learn the speed claim and the asterisks attached to it, the cases where Julia is the clear winner, and the cases where it is the wrong tool. If you want to actually understand the language rather than collect snippets, enroll now and start writing Julia the way its designers intended.