Julia v1.14 Release Notes
New language features
It is now possible to control which version of the Julia syntax will be used to parse a package by setting the
compat.juliaorsyntax.julia_versionkey in Project.toml. This feature is similar to the notion of "editions" in other language ecosystems and will allow non-breaking evolution of Julia syntax in future versions. See the "Syntax Versioning" section in the code loading documentation (#60018).ᵅ(U+U+1D45),ᵋ(U+1D4B),ᶲ(U+1DB2),˱(U+02F1),˲(U+02F2), andₔ(U+2094) can now also be used as operator suffixes, accessible as\^alpha,\^epsilon,\^ltphi,\_<,\_>, and\_schwaat the REPL (#60285).The
@labelmacro can now create labeled blocks that can be exited early withbreak name [value]. Use@label name exprfor named blocks or@label exprfor anonymous blocks. Anonymous@labelblocks participate in the default break scope: a plainbreakorbreak _exits the innermost breakable scope, whether it is a loop or an@labelblock. Thecontinuestatement also supports labels withcontinue nameto continue a labeled loop (#60481).typegroupblocks allow defining mutually recursive struct types that reference each other in their field types. All types in the group are resolved atomically at the end of the block (#60569).A macrocall directly inside parens — e.g.
(@info "msg" x=1)— may now continue its arguments on subsequent lines, so each argument of a long macro call can be placed on its own line without switching to the comma separated call syntax (#60181).Primitive types with non-byte-multiple logical widths can now be defined (#61359).
Introduced explicitly wrapping arithmetic operators
+%,-%,*%to annotate arithmetic operations that are semantically safe to wrap/overflow. Their behavior is currently identical to the default+,-,*operators. However, in a future version, there may be opt-in support to detect unannotated wrapping in the default operators (#50790).@sync,Threads.@threadsandExperimental.@syncblocks now scope a cancellation source (seeBase.CancellationTokenSource) over their children, so cancelling an enclosing scope reaches everything spawned within, and the blocks' teardown awaits internal tasks per the requested cancellation severity (#60281).Task cancellation is now supported, organized around cancellation tokens:
Base.CancellationTokenSourceis a level-triggered, tree-structured cancellation scope (cancelling a source cancels its whole subtree, at monotonically escalating severities), andBase.CancellationTokenis its observe/wait view. The token governing a computation is carried as a scoped value (Base.CANCEL_TOKEN, established with the standardScopedValuesAPI) that propagates to child tasks; blocking operations (wait,lock, Channel operations,sleep, stream and command I/O, Sockets, FileWatching, ...) accept acancelkeyword argument defaulting to the scoped token and throw aBase.CancellationRequestwhile it is cancelled. Cancellation is uniformly level-triggered: cleanup code that must block under a cancelled scope shields itself withcancel = nothing(or by scopingBase.CANCEL_TOKEN => nothingover a whole block). Compute-bound code can opt into cancellation with theBase.@cancel_checkcancellation point. A long-running foreign call can be made cancellable with@ccall cancel_handler=(fn, state) ...: cancelling the governing token runs the C-callablefn(state, severity)on the thread executing the call, signal-handler-style, so it can tell the library to return early (the pending cancellation is then thrown at the next cancellation point). Calls into libraries audited for asynchronous unwinding can be annotated@ccall reset_safe=true ...instead, letting a cancellation unwind the foreign computation at an arbitrary instruction;BigInt(GMP) arithmetic uses this, so checkless bignum loops now cancel cleanly at the first ^C. In interactive sessions, ^C now cancels the current evaluation's cancellation scope (instead of throwing anInterruptExceptioninto whatever code happened to be running), and a fresh ^C epoch is re-armed at each prompt; a script that catches a ^C cancellation continues under the cancelled scope unless it re-arms one itself (ScopedValues.@with Base.CANCEL_TOKEN => Base.sigint_new_episode!() ...) (#60281).
Language changes
Type{T} <: Snow holds only if every type==toTis an instance ofS, fixing a long-standing soundness hole where e.g.Type{Int} <: DataTypeheld even though types likeTuple{S} where S<:Intare==(andisa) their canonical spelling without beingDataTypes. In particularType{T}is no longer a subtype of any single kind: use a union of kinds instead (e.g.Type{Int} <: Union{DataType,UnionAll}holds).isaand dispatch of type values are unaffected, and a method onType{Int}remains more specific than one onDataType(#33136, #62141).
Compiler/Runtime improvements
Type inference now refines field types through conditional checks and call signatures. For example, after
if !isnothing(x.field), inference knowsx.fieldis notnothingwithin the branch. Similarly, after a call likefunc(x.field)wherefunc(::Int)is the only matching method, inference refinesx.fieldtoInt. This works for immutable struct fields andconstfields of mutable structs. Mutable (non-const) fields are not supported due to the lack of per-object memory effect tracking; for those, the recommended pattern remains storing the field value in a local variable before the check (e.g.val = x.field; if !isnothing(val) ... end) (#41199, #47574).Stack traces now show full method signatures with argument types for inlined frames, matching the display of non-inlined frames (#53925).
Stack traces of errors raised while loading code no longer show the internals of the code loading machinery, which are collapsed to the single frame that entered loading. Frames for user code that runs during loading are unaffected. Set the
JULIA_STACKTRACE_FULL_LOADINGenvironment variable totrueto show them (#52988).Parallel package precompilation now coordinates CPU usage across both the precompile worker processes and the LLVM threads each spawns to compile its native image, sharing a single thread budget so idle cores are filled during the long tail without oversubscribing the machine when many packages compile at once. The total budget can be set with the new
JULIA_PRECOMPILE_THREADSenvironment variable (#61958).Parallel package precompilation no longer attempts packages whose dependencies failed to precompile; they are reported as skipped instead, and extensions of a failed package are dropped silently. Pass
skip_dependents=falsetoBase.Precompilation.precompilepkgsto attempt the packages anyway. A newforcekeyword recompiles packages whose cache files are already fresh (#63122).Coverage reports now include code executed by the interpreter, such as top-level statements and method bodies run with
--compile=min. Consequently, LCOV output and.covfiles may contain source lines that were absent in earlier releases (#62514).Coverage and allocation tracking use separate unordered atomic loads and stores. This avoids the atomic read-modify-write overhead reported in #62424 while keeping concurrent accesses well-defined; execution counts may still be inaccurate when the same source line runs on multiple threads (#62724).
--code-coverage=userno longer includes inlined Base methods whose module cannot be recovered from debug information. This prevents coverage from writing.covfiles for Base sources into the Julia installation (#62514).Coverage now records only whether each source line ran by default, and reports a count of 1 for executed lines in
.covfiles and LCOV tracefiles. Use--code-coverage-mode=countto collect execution counts instead. The defaulthitmode avoids the load and increment at each instrumentation point (#62724).Coverage runs can reuse instrumented package images across processes. The counter mode is part of the cache identity;
user,all, and@pathselect the same image variants and filter the counters reported. Count images can also serve hit requests (#62724).--code-coverage=allno longer invalidates system-image code at startup. To collect coverage from that code, build Julia withJULIA_COVERAGE_IMAGES=1, which instruments the system image and bundled package images in hit mode.@pathinstruments newly compiled and interpreted code likeuser, while also reporting compatible image counters under the selected path (#62724).Resolved global variable accesses now carry the binding partition they act on through lowered code, instead of code generation re-deriving it by scanning a binding's partitions. After optimization, an access that previously appeared as a
GlobalRef,getglobalorsetglobal!may instead appear as aCore.BindingPartition, as the left-hand side of an assignment to one, or as a call to one of the newCore.getglobal_partition,Core.setglobal_partition,Core.swapglobal_partition,Core.modifyglobal_partition,Core.replaceglobal_partition,Core.setglobalonce_partition,Core.isdefinedglobal_partitionorCore.depwarn_partitionbuiltin function. This does not change the meaning of the program, but packages that inspect optimized IR (e.g. fromcode_typed) will encounter these new forms. See the "Lowered form" section of the developer documentation for their semantics (#62452).
Command-line option changes
-P <project>is now a shorthand for--project <project>(#59867).--code-coverage=@<path>and--track-allocation=@<path>now restrict tracking to the specified file or directory tree. For example,@/src/Footracks/src/Foo/x.jl, but not/src/Foobar/x.jl. Specifying the filesystem root as@/tracks every absolute path.Base.is_file_trackednow returnsfalsewhen Julia was not started with either@<path>option (#62514).
Multi-threading changes
The return type of
fetch(::Task)is now inferred precisely when inference can determine the code the task was created to run (for examplefetch(Threads.@spawn f(x))), instead of always beingAny. Correspondingly, assigning to theresultfield of aTaskvia property syntax (t.result = v) now throws an error: the result of a task is determined by the return value of its code, and the runtime and the compiler now rely on this correspondence. To pass a value to a suspended task, useschedule(t, val)oryieldto(t, val)(#59221).New functions
Threads.atomic_fence_heavyandThreads.atomic_fence_lightprovide support for asymmetric atomic fences, speeding up atomic synchronization where one side of the synchronization runs significantly less often than the other (#60311).Threads.@threadsnow supports array comprehensions with syntax like@threads [f(i) for i in 1:n], filtered comprehensions like@threads [f(i) for i in 1:n if condition(i)], typed comprehensions like@threads Float64[f(i) for i in 1:n], and multi-dimensional comprehensions like@threads [f(i,j) for i in 1:n, j in 1:m](preserves dimensions). All scheduling options (:static,:dynamic,:greedy) are supported. Results preserve element order for:staticand:dynamicscheduling;:greedydoes not guarantee order. Non-indexable iterators are also supported (#59019).The task scheduler now avoids O(nthreads) wake overhead on every
@spawn, significantly reducing threading overhead particularly on highly oversubscribed machines. Benchmarks show up to 1000x reduction in spawn time in such scenarios (#61826).Threads.Atomicnow supports the reference form of the@atomic,@atomicswap,@atomicreplace, and@atomiconcemacros (e.g.@atomic a[],@atomic a[] = v,@atomic a[] += 1), which allows the memory ordering to be specified explicitly and makes atomic read-modify-write operations syntactically clear (#62382).
Build system changes
New library functions
tap(f)creates a function that callsf(x)for side effects and returnsx(#61340).unsplat(f)creates a function that bundles its arguments into a tuple and passes them tof; it is the inverse ofsplat(#62714).Base.set_binding_visibility!sets the declared visibility (:none,:public, or:export) of a name in a module, allowing anexportorpublicdeclaration to be retracted programmatically (#62131).Base.generating_output()has been madepublic(but not exported) to allow checking whether the current process is performing compilation for a pkgimage/sysimage (#61224).Base.isfieldatomic(t, s)has been madepublic(but not exported); it reports whether a fieldsof a typetis declared@atomic.Base.raw_substringis an unexported, public constructor to build aSubStringwithout checking for valid string indices.Base.unannotate(::AnnotatedString)returns the underlying un-annotated string of the input string.Base.include_mapexprs(mod)is an unexported, public function returning the non-identitymapexprfunctions used byinclude(mapexpr, …)calls while loading the package rooted atmod, keyed by(including_module, absolute_path). The table is stored inside the package image, so it survives precompilation; revision tools (e.g. Revise) use it to re-apply the original transform when aninclude(mapexpr, …)-ed file is edited.
New library features
IOContextsupports a new booleanhexunsignedoption that allows for printing unsigned integers in decimal instead of hexadecimal (#60267).lazy"..."strings now support a flaglazy"..."cthat addscompactandlimitflags to theIOContextfor final output-string generation (#61887).The
StringViewtype wraps anAbstractVector{UInt8}and interprets it as a UTF-8 encoded string, superseding the StringViews.jl package (#60526).Package precompilation now supports running precompilation in a background task and has new interactive keyboard controls:
cto cleanly cancel immediately,dto detach,ifor a profile peek,vto toggle verbose mode showing elapsed time, CPU%, and memory usage, and?for help (#60943).Instances of an
Enumcan now be given their own docstrings within the@enumdefinition (#61955).New methods
readdir(path, DirEntry)andreaddir(::DirEntry, DirEntry)return directory contents along with the type of the entries in a vector of newDirEntryobjects to provide more efficientisfileetc. checks.readdir(::DirEntry)accepts aDirEntryas input and, likereaddir(::AbstractString), returns aVector{String}of names.DirEntryis exported fromBase(#55358).New public but unexported function
Base.unsetindex!unsets the reference from an array or aMemoryRefto its value, making it as if it was uninitialized.Calls to
waiton one-shotTimers that have already triggered no longer throwEOFError. Previously only the firstwaitreturned and subsequentwaitcalls would throw (#62539)When the display height is too small to show any array entries, the
text/plainarray display (used e.g. by the REPL and when logging values with@infoetc.) now shows as many entries as fit on a single line, truncated to the display width, instead of showing no data at all (#62543).The element type of broadcast expressions now uses regular inference machinery rather than an idiosyncratic heuristic. This can help fused or empty broadcasts infer to more precise element types (#62564).
Standard library changes
codepoint(c)now succeeds for overlong encodings.Base.ismalformed,Base.isoverlong, andBase.show_invalidare nowpublicand documented (but not exported) (#55152).The
Precompilingmessages printed while loading name packages without their uuid when the name is unambiguous in the environment, name extensions by their parent package, and say which dependency is already loaded at a different version when that is why a cache was not reused (#63185).
JuliaSyntaxHighlighting
LinearAlgebra
Markdown
Support "raw" or "inline" HTML inside Markdown data (#60629, #60632, #60732).
Support autolinks for email addresses (#60570).
Many improvements and bugfixes for rendering Markdown lists in a terminal (#55456, #60519).
Strikethrough text via
~strike~or~~through~~is now supported by the Markdown parser (#60537).Many, many bug fixes and minor tweaks; overall behavior is now much closer to CommonMark (#59977, #60502).
Profile
Random
REPL
Tab completion now supports
\escapefor⎋and\xmarkfor✗.The Julia REPL now emits OSC 133 semantic prompt markers for terminal integration.
A
using/importstatement that loads several packages, such asusing A, B, C, now precompiles all of them (and the extensions they make loadable) in a single parallel session, rather than one session per package (#63185).
Sockets
getsocknamenow also accepts aUDPSocket, returning the address and port it is bound to (#63091).
SharedArrays
close(::SharedArray)eagerly releases the shared-memory mappings referenced through the array on all processes, e.g. so the file backing a file-backedSharedArraycan be deleted immediately (#62488).
Test
Pressing
^Ctwice at an emptyjulia>prompt now cancels all still-running work started by earlier evaluations (e.g. a runaway@asynctask spewing output): each REPL evaluation runs under its own cancellation source, linked under one session-level source that the repeated press cancels (#47839).
Test
@test,@test_throws, and@test_brokennow support acontextkeyword argument that provides additional information displayed on test failure. This is useful for debugging which specific case failed in parameterized tests (#60501).@test_throws,@test_warn,@test_nowarn,@test_logs, and@test_deprecatednow supportbrokenandskipkeyword arguments for consistency with@test(#60543).New functions
detect_closure_boxesanddetect_closure_boxes_allfind methods that allocateCore.Boxin their lowered code, which can indicate performance issues from captured variables in closures (#60478).detect_unbound_argsnow uses a conservative rule derived from how subtyping assigns values to static parameters, instead of older heuristics. It detects previously missed possibly-unbound parameters (such asf(::Type{<:T}) where {T}, which leavesTunbound when called withUnion{}, orf(::Vector{<:T}) where {T}with aVector{Union{}}argument), and no longer reports methods whose problematic calls are all shadowed by more specific methods (such as af(::Type{Union{}})fallback), or whose lowered bodies never read the possibly-unbound parameters. Parameters left unbound only by calls withUnion{}type parameters are reported only with the newambiguous_bottom=truekeyword argument, as fordetect_ambiguities(#62405).
Dates
unix2datetimenow accepts a keyword argumentlocaltime=trueto use the host system's local time zone instead of UTC (#50296).
InteractiveUtils
less/@lessandedit/@editare now supported for documented variables (#53539).A new
@methodsmacro lists all methods applicable to a call expression, using the types of the given arguments, e.g.@methods isvalid('a', 1)or@methods isvalid(::AbstractChar, ::Integer)(#62311).
Dates
TOML
The parsing functions (
TOML.parsefile,TOML.parse, and theirtryvariants) can now capture the comments of a document into aTOML.Commentsobject via the newcommentskeyword argument, andTOML.printcan write them back out via its newcommentskeyword argument. This allows modifying a TOML file without losing its comments (#62672).
External dependencies
Tooling Improvements
Deprecated or removed
Storing into a
Threads.Atomicwith the plaina[] = vform (i.e.setindex!) is deprecated in favor of@atomic a[] = v. The plain form makes read-modify-write expressions such asa[] += 1look atomic even though they expand to a separate, non-atomic load and store; use@atomic a[] += 1orThreads.atomic_add!for an atomic update. Reading witha[]is unchanged (#62382).