Julia solves the two-language problem: write Python-readable code that compiles to LLVM and runs at C speed. Multiple dispatch selects function methods based on all argument types — enabling generic algorithms that specialize automatically. DataFrames.jl provides pandas-like tabular operations with type inference. Flux.jl builds neural networks as composable Julia functions — no separate computation graph. DifferentialEquations.jl solves ODEs, SDEs, and DAEs with state-of-the-art algorithms. The JIT compiler eliminates overhead in hot loops. Claude Code generates Julia functions, DataFrames pipelines, Flux models, differential equation systems, and the package configurations for production scientific computing workflows.
CLAUDE.md for Julia Projects
## Julia Stack
- Version: Julia >= 1.10 (LTS)
- Package management: Pkg.jl with Project.toml + Manifest.toml — always activate env
- DataFrames: DataFrames.jl >= 1.6 — use groupby/transform/combine patterns
- ML: Flux.jl for neural nets, MLJ.jl for classical ML with unified API
- Plots: Makie.jl (publication quality) or Plots.jl (quick exploration)
- Testing: Test stdlib — @test, @testset, @test_throws
- Performance: @benchmark from BenchmarkTools, @code_warntype for type stability
- REPL: use Revise.jl in development for hot reloading
Julia Fundamentals: Multiple Dispatch
# src/dispatch_demo.jl — multiple dispatch enables generic programming
using Statistics
# Multiple dispatch: define behavior for each type combination
abstract type FinancialInstrument end
struct Order <: FinancialInstrument
id::String
amount::Float64
currency::String
status::Symbol # :pending, :processing, :shipped, :delivered
end
struct Invoice <: FinancialInstrument
id::String
amount::Float64
due_date::Date
paid::Bool
end
# Same function name, different behavior per type — no if/else on types
function calculate_fee(order::Order)
if order.amount > 1000
return order.amount * 0.02
else
return order.amount * 0.03
end
end
function calculate_fee(invoice::Invoice)
invoice.paid ? 0.0 : invoice.amount * 0.015
end
# Works for ANY combination of FinancialInstrument subtypes
function calculate_total_fees(instruments::Vector{<:FinancialInstrument})
sum(calculate_fee, instruments)
end
# Method with multiple dispatch on two arguments
function compare_value(a::Order, b::Order)
a.amount <=> b.amount
end
function compare_value(a::Invoice, b::Order)
a.amount - calculate_fee(a) <=> b.amount - calculate_fee(b)
end
# Parametric types: type-safe containers
struct TypedPair{T, S}
first::T
second::S
end
function swap(p::TypedPair{T, S}) where {T, S}
TypedPair{S, T}(p.second, p.first)
end
DataFrames Pipeline
# src/analytics/order_analytics.jl — tabular data with DataFrames.jl
using DataFrames
using CSV
using Dates
using Statistics
function load_orders(path::String)::DataFrame
df = CSV.read(path, DataFrame,
types = Dict(
:order_id => String,
:customer_id => String,
:amount => Float64,
:created_at => DateTime,
:status => String,
)
)
return df
end
function clean_and_enrich(df::DataFrame)::DataFrame
return df |>
# Filter valid rows
x -> filter(row -> !ismissing(row.amount) && row.amount > 0, x) |>
# Add derived columns
x -> transform(x,
:created_at => (d -> Date.(d)) => :order_date,
:created_at => (d -> month.(d)) => :order_month,
:created_at => (d -> year.(d)) => :order_year,
:amount => (a -> ifelse.(a .> 1000, "high_value", "standard")) => :segment,
) |>
# Sort by date descending
x -> sort(x, :created_at, rev=true)
end
function monthly_revenue_report(df::DataFrame)::DataFrame
# Group → aggregate
report = combine(
groupby(df, [:order_year, :order_month]),
:amount => sum => :total_revenue,
:amount => mean => :avg_order_value,
:order_id => length => :order_count,
:customer_id => (x -> length(unique(x))) => :unique_customers,
)
# Add month-over-month growth
sort!(report, [:order_year, :order_month])
transform!(report,
:total_revenue => (r -> [missing; diff(r) ./ r[1:end-1] * 100]) => :revenue_growth_pct
)
return report
end
function customer_cohort_analysis(df::DataFrame)::DataFrame
# Find each customer's first order date
first_orders = combine(
groupby(df, :customer_id),
:order_date => minimum => :cohort_date,
)
first_orders.cohort_month = Dates.firstdayofmonth.(first_orders.cohort_date)
# Join back to get cohort for each order
enriched = innerjoin(df, first_orders, on=:customer_id)
# Calculate months since cohort
transform!(enriched,
[:order_date, :cohort_month] =>
((d, c) -> Dates.value.(Dates.Month.(d - c))) =>
:months_since_cohort
)
# Retention by cohort
retention = combine(
groupby(enriched, [:cohort_month, :months_since_cohort]),
:customer_id => (x -> length(unique(x))) => :active_customers,
)
return retention
end
Flux.jl Neural Networks
# src/ml/classifier.jl — neural network with Flux.jl
using Flux
using Flux: train!, DataLoader, logitcrossentropy
using MLUtils: splitobs
using Statistics
# Build model as composed Julia functions
function build_classifier(input_dim::Int, hidden_dim::Int, num_classes::Int)
model = Chain(
Dense(input_dim => hidden_dim, relu),
Dropout(0.3),
Dense(hidden_dim => hidden_dim ÷ 2, relu),
Dropout(0.2),
Dense(hidden_dim ÷ 2 => num_classes),
)
return model
end
# Training loop with explicit gradient descent
function train_model!(
model,
X_train::Matrix{Float32},
y_train::Vector{Int},
X_val::Matrix{Float32},
y_val::Vector{Int};
epochs::Int = 50,
batch_size::Int = 64,
lr::Float64 = 1e-3,
)
# One-hot encode labels
num_classes = maximum(y_train)
y_onehot = Flux.onehotbatch(y_train, 1:num_classes)
train_loader = DataLoader(
(X_train, y_onehot),
batchsize=batch_size,
shuffle=true,
)
opt_state = Flux.setup(Adam(lr), model)
history = (; train_loss=Float64[], val_accuracy=Float64[])
for epoch in 1:epochs
epoch_losses = Float64[]
for (x_batch, y_batch) in train_loader
# Compute gradients and update
loss, grads = Flux.withgradient(model) do m
logitcrossentropy(m(x_batch), y_batch)
end
Flux.update!(opt_state, model, grads[1])
push!(epoch_losses, loss)
end
# Validation
val_preds = Flux.onecold(model(X_val))
val_acc = mean(val_preds .== y_val)
push!(history.train_loss, mean(epoch_losses))
push!(history.val_accuracy, val_acc)
if epoch % 10 == 0
@info "Epoch $epoch" train_loss=round(mean(epoch_losses), digits=4) val_acc=round(val_acc, digits=4)
end
end
return history
end
# Transfer learning with pretrained features
function fine_tune_model(pretrained_backbone, X_features, y, num_classes)
# Freeze backbone, add classification head
head = Chain(
Dense(size(X_features, 1) => 256, relu),
Dense(256 => num_classes),
)
# Flux.freeze! prevents gradient updates to frozen layers
backbone_frozen = Flux.freeze!(pretrained_backbone)
full_model = Chain(backbone_frozen, head)
return full_model
end
Performance Profiling
# src/performance/benchmarks.jl — measure and optimize Julia performance
using BenchmarkTools
# Check type stability — @code_warntype highlights inferred types
function unstable_sum(xs)
total = 0 # Int, but xs might be Float64 — type instability!
for x in xs
total += x
end
return total
end
function stable_sum(xs::Vector{Float64})::Float64
total = 0.0 # Float64 matches xs element type
for x in xs
total += x
end
return total
end
# @benchmark runs many iterations and reports statistics
function compare_implementations()
data = rand(Float64, 100_000)
suite = BenchmarkGroup()
suite["unstable"] = @benchmarkable unstable_sum($data)
suite["stable"] = @benchmarkable stable_sum($data)
suite["builtin"] = @benchmarkable sum($data)
results = run(suite, verbose=false)
for (name, result) in results
println("$name: $(BenchmarkTools.minimum(result))")
end
end
# SIMD vectorization with @simd for inner loops
function dot_product_fast(a::Vector{Float64}, b::Vector{Float64})
@assert length(a) == length(b)
result = 0.0
@simd for i in eachindex(a)
@inbounds result += a[i] * b[i]
end
return result
end
# Parallel computation
using Base.Threads
function parallel_map(f, xs::Vector)
results = Vector{Any}(undef, length(xs))
@threads for i in eachindex(xs)
results[i] = f(xs[i])
end
return results
end
Testing with Test stdlib
# test/runtests.jl
using Test
using DataFrames
include("../src/analytics/order_analytics.jl")
@testset "Order Analytics" begin
@testset "clean_and_enrich" begin
df = DataFrame(
order_id=["o1", "o2", "o3"],
customer_id=["c1", "c1", "c2"],
amount=[100.0, missing, 1500.0],
created_at=[DateTime(2026,1,15), DateTime(2026,2,20), DateTime(2026,1,5)],
status=["shipped", "pending", "delivered"],
)
result = clean_and_enrich(df)
@test nrow(result) == 2 # Missing amount row removed
@test "order_date" in names(result)
@test "segment" in names(result)
@test result[result.amount .> 1000, :segment][1] == "high_value"
end
@testset "monthly_revenue_report" begin
df = DataFrame(
order_id=["o1", "o2", "o3", "o4"],
customer_id=["c1", "c2", "c1", "c3"],
amount=[100.0, 200.0, 150.0, 300.0],
order_date=[Date(2026,1,1), Date(2026,1,15), Date(2026,2,1), Date(2026,2,15)],
order_year=[2026, 2026, 2026, 2026],
order_month=[1, 1, 2, 2],
)
report = monthly_revenue_report(df)
@test nrow(report) == 2
@test report[1, :total_revenue] ≈ 300.0
@test report[2, :order_count] == 2
end
end
For the Python data science stack with pandas and scikit-learn that Julia’s DataFrames.jl and Flux.jl replace in performance-critical scenarios, see the Python data science guide. For the Polars high-performance DataFrame library that brings Rust-level speed to Python without JIT compilation, the Polars guide covers lazy evaluation and streaming. The Claude Skills 360 bundle includes Julia skill sets covering multiple dispatch, DataFrames pipelines, and Flux.jl models. Start with the free tier to try Julia program generation.