cross-version compatibility


Compat Package for Julia

Build Status Build status

Compat Compat Compat Compat

The Compat package is designed to ease interoperability between older and newer versions of the Julia language. In particular, in cases where it is impossible to write code that works with both the latest Julia master branch and older Julia versions, or impossible to write code that doesn't generate a deprecation warning in some Julia version, the Compat package provides a macro that lets you use the latest syntax in a backwards-compatible way.

This is primarily intended for use by other Julia packages, where it is important to maintain cross-version compatibility.


To use Compat in your Julia package, add a line Compat to the REQUIRE file in your package directory. Then, in your package, shortly after the module statement include lines like these:

using Compat
import Compat.String

and then as needed add

@compat ...compat syntax...

wherever you want to use syntax that differs in the latest Julia master (the development version of Julia). The compat syntax is usually the syntax on Julia master. However, in a few cases where this is not possible, a slightly different syntax might be used. Please check the list below for the specific syntax you need.

Supported syntax

Currently, the @compat macro supports the following syntaxes:

  • @compat (a::B{T}){T}(c) = d — the Julia 0.5-style call overload

  • @compat(get(io, s, false)), with s equal to :limit, :compact or :multiline, to detect the corresponding print settings (performs useful work only on Julia 0.5, defaults to false otherwise)

  • @compat Nullable(value, hasvalue) to handle the switch from the Nullable :isnull field to :hasvalue field (#18510)

  • @compat x .= y converts to an in-place assignment to x (via broadcast!) (#17510). However, beware that .= in Julia 0.4 has the precedence of ==, not of assignment =, so if the right-hand-side y includes expressions with lower precedence than == you should enclose it in parentheses x .= (y) to ensure the correct order of evaluation. Also, x .+= y converts to x .= (x .+ y), and similarly for the other updating assignment operators (.*= and so on).

  • @compat Array{<:Real}, @compat Array{>:Int}, and similar uses of <:T (resp. >:T) to define a set of "covariant" (resp. "contravariant") parameterized types (#20414). In 0.5, this only works for non-nested usages (e.g. you can't define Array{<:Array{<:Real}}).

  • @compat abstract type T end and @compat primitive type T 8 end to declare abstract and primitive types. #20418 This only works when @compat is applied directly on the declaration.

  • @compat A{T} = B{T} or @compat const A{T} = B{T} to declare type alias with free parameters. #20500. Use const A = B{T} or const A = B for type alias without free parameters (i.e. no type parameter on the left hand side).

  • @compat Base.IndexStyle(::Type{<:MyArray}) = IndexLinear() and @compat Base.IndexStyle(::Type{<:MyArray}) = IndexCartesian() to define traits for abstract arrays, replacing the former Base.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearFast() and Base.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearSlow(), respectively.

  • Compat.collect(A) returns an Array, no matter what indices the array A has. #21257

  • @compat foo(::CartesianRange{N}) to replace the former foo(::CartesianRange{CartesianIndex{N}}) (#20974). Note that CartesianRange now has two type parameters, so using them as fields in other structs requires manual intervention.

Module Aliases

  • In 0.6, some 0.5 iterator functions have been moved to the Base.Iterators module. Code can be written to work on both 0.5 and 0.6 by importing or using the Compat.Iterators module instead. (#18839)

  • using Compat.Test, using Compat.SharedArrays, using Compat.Mmap, and using Compat.DelimitedFiles are provided on versions older than 0.7, where these are not yet part of the standard library. (#23931)

  • using Compat.Base64 is provided on versions older than 0.7, where this library is not yet a part of the standard library. (#24361)

  • using Compat.Dates is provided on versions older than 0.7, where this library is not yet a part of the standard library. (#24459)

  • using Compat.Unicode is provided on versions older than 0.7, where this library is not yet a part of the standard library. (#25021)

  • using Compat.Printf is provided on versions older than 0.7, where this library is not yet a part of the standard library. (#25056)

  • using Compat.IterativeEigensolvers is provided on versions older than 0.7, where this library is not yet a part of the standard library. (#24714)

  • using Compat.SuiteSparse is provided on versions older than 0.7, where this library is not yet part of the standard library (#24648).

New functions, macros, and methods

  • @views takes an expression and converts all slices to views (#20164), while @view (#16564) converts a single array reference to a view (#20164).

  • @__dot__ takes an expression and converts all assignments, function calls, and operators to their broadcasting "dot-call" equivalents (#20321). In Julia 0.6, this can be abbreviated @., but that macro name does not parse in earlier Julia versions. For this to work in older versions of Julia (prior to 0.5) that don't have dot calls, you should instead use @dotcompat, which combines the @__dot__ and @compat macros.

  • normalize and normalize!, normalizes a vector with respect to the p-norm (#13681)

  • redirect_stdout, redirect_stderr, and redirect_stdin take an optional function as a first argument, redirect_std*(f, stream), so that one may use do block syntax (as first available for Julia 0.6)

  • unsafe_get returns the :value field of a Nullable object without any null-check and has a generic fallback for non-Nullable argument (#18484)

  • isnull has a generic fallback for non-Nullable argument

  • transcode converts between UTF-xx string encodings in Julia 0.5 (as a lightweight alternative to the LegacyStrings package) (#17323)

  • (typically used infix as f ∘ g) for function composition can be used in 0.5 and earlier (#17155)

  • >:, a supertype operator for symmetry with issubtype (A >: B is equivalent to B <: A), can be used in 0.5 and earlier (#20407).

  • The method of ! to negate functions (typically used as a unary operator, as in !isinteger) can be used in 0.5 and earlier (#17155).

  • iszero(x) efficiently checks whether x == zero(x) (including arrays) can be used in 0.5 and earlier (#19950).

  • .& and .| are short syntax for broadcast(&, xs...) and broadcast(|, xs...) (respectively) in Julia 0.6 (only supported on Julia 0.5 and above) (#17623)

  • Compat.isapprox with nans keyword argument (#20022)

  • Compat.readline with chomp keyword argument (#20203)

  • take! method for Tasks since some functions now return Channels instead of Tasks (#19841)

  • The isabstract, parameter_upper_bound, typename reflection methods were added in Julia 0.6. This package re-exports these from the Compat.TypeUtils submodule. On earlier versions of julia, that module contains the same functions, but operating on the pre-0.6 type system representation.

  • broadcast is supported on tuples of the same lengths on 0.5. (#16986)

  • zeros and ones support an interface the same as similar (#19635)

  • convert can convert between different Set types on 0.5 and below. (#18727)

  • isassigned(::RefValue) is supported on 0.5 and below. (#18082)

  • unsafe_trunc(::Type{<:Integer}, ::Integer) is supported on 0.5. (#18629)

  • bswap is supported for Complex arguments on 0.5 and below. (#21346)

  • Compat.invokelatest is equivalent to Base.invokelatest in Julia 0.6, but works in Julia 0.5+, and allows you to guarantee that a function call invokes the latest version of a function (#19784).

  • Compat.invokelatest supports keywords (#22646).

  • Compat.StringVector is supported on 0.5 and below. On 0.6 and later, it aliases Base.StringVector. This function allocates a Vector{UInt8} whose data can be made into a String in constant time; that is, without copying. On 0.5 and later, use String(...) with the vector allocated by StringVector as an argument to create a string without copying. Note that if 0.4 support is needed, Compat.UTF8String(...) should be used instead. (#19449)

  • ==(::Period, ::Period) and isless(::Period, ::Period) is supported for 0.5 and below. Earlier versions of Julia only supported limited comparison methods between Periods which did not support comparing custom Period subtypes. (#21378)

  • @__MODULE__ is aliased to current_module() for Julia versions 0.6 and below. Versions of Base.binding_module, expand, macroexpand, and include_string were added that accept a module as the first argument. (#22064)

  • Cmd elements can be accessed as if the Cmd were an array of strings for 0.6 and below (#21197).

  • Val(x) constructs Val{x}(). (#22475)

  • The reshape and ntuple APIs are extended to support Val{x}() arguments on 0.6 and below.

  • chol and chol! for UniformScalings (#22633).

  • logdet for Numbers (#22629).

  • fieldcount is equivalent to nfields for Julia versions 0.6 and below and is used to determine the number of fields in a data type (#22350).

  • There are versions of InexactError, DomainError, and OverflowError that take the same arguments as introduced in Julia 0.7-DEV (#20005, #22751, #22761).

  • retry for the more flexible retry method introduced in 0.6 which includes support for kwargs (#19331, #21419).

  • Base.rtoldefault how takes a third parameter atol. The two argument form is deprecated in favor of the three arguments form with atol=0.

  • The corrected optional argument of cov becomes a keyword argument. Due to conflict with 0.5 deprecation, cov(::AbstractVector; corrected=) and cov(::AbstractVector, ::AbstractVector; corrected=) are only available on 0.6. (#21709)

  • equalto constructs an EqualTo object that can be used as a predicate (#23812).

  • *(::Union{Char,AbstractString},::Union{Char,AbstractString}) concatenation. (#22512)

  • diagm and spdiagm accept pairs mapping diagonals to vectors (#24047, #23757)

  • Constructors for Matrix{T}, Array{T}, and SparseMatrixCSC{T} from UniformScaling (#24372, #24657)

  • Uninitialized and uninitialized with corresponding Array constructors (#24652).

  • BitArray constructors for uninitialized (#24785).

  • @compat finalizer(func, obj) with the finalizer to run as the first argument and the object to be finalized as the second (#24605).

  • IOContext accepting key-value Pairs (#23271).

  • pairs for iterating over key-value Pairs (#22907).

  • get do-block syntax supported when using ENV (#23412).

  • Some{T} wraps T to signify that a result of T<:Void is expected (#23642).

  • replace accepts a pair of pattern and replacement, with the number of replacements as a keyword argument (#25165).

  • CartesianIndices and LinearIndices types represent cartesian and linear indices of an array (respectively), and indexing such objects allows translating from one kind of index to the other (#25113).


  • $ is now xor or (#18977)

  • num and den are now numerator and denominator (#19246)

  • takebuf_array is now a method of take!. takebuf_string(io) becomes String(take!(io)) (#19088)

  • is_apple, is_bsd, is_linux, is_unix, and is_windows are now Sys.isapple, Sys.isbsd, Sys.islinux, Sys.isunix, and Sys.iswindows, respectively. These are available in the Compat.Sys submodule. (#22182)

  • readstring is replaced by methods of read. (#22864)

    read(::IO, ::Type{String}), read(::AbstractString, ::Type{String}), and read(::Cmd, ::Type{String}) are defined for 0.6 and below.

  • Range is now AbstractRange (#23570)

  • select* functions (select, select!, selectperm, selectperm!) are renamed to partialsort* (partialsort, partialsort!, partialsortperm, partialsortperm!) (#23051)

  • ctranspose and ctranspose! are now adjoint and adjoint! (#23235)

  • Math constants (π, pi, e, γ, eulergamma, catalan, φ, golden) are moved to the MathConstants module (available as Compat.MathConstants). The name exported from Base for e is changed to . (#23427)

  • isleaftype is now isconcrete (#23666)

  • IntSet is now BitSet (#24282)

  • Complex32, Complex64, and Complex128 are now ComplexF16, ComplexF32, and ComplexF64, respectively (#24647).

  • JULIA_HOME is now Sys.BINDIR, available in the Compat.Sys submodule. (#25102)

  • Associative is now AbstractDict (#25012).

  • indices is now axes (#25057). This function is not exported from Compat to avoid conflicts with AxisArrays and other such packages.

  • Void is now Nothing with an alias Cvoid for C interop (#25162).

  • unshift! and shift! are now pushfirst! and popfirst! (#25100).

  • copy! and unsafe_copy! are now copyto! and unsafe_copyto! ([#24808]).

  • ipermute! is now invpermute! (#25168).

New macros

  • @__DIR__ has been added (#18380)

  • @vectorize_1arg and @vectorize_2arg are deprecated on Julia 0.6 in favor of the broadcast syntax (#17302). Compat.@dep_vectorize_1arg and Compat.@dep_vectorize_2arg are provided so that packages can still provide the deprecated definitions without causing a depwarn in the package itself before all the users are upgraded.

Packages are expected to use this until all users of the deprecated vectorized function have migrated. These macros will be dropped when the support for 0.6 is dropped from Compat.

  • @nospecialize has been added (#22666).

Other changes

  • On versions of Julia that do not contain a Base.Threads module, Compat defines a Threads module containing a no-op @threads macro.

  • The Expr(:macrocall) has an extra initial argument __source__, which can be tested for with Compat.macros_have_sourceloc.

New types

  • Compat.AbstractDateTime is an alias for Compat.Dates.AbstractDateTime as of ([#25227]) and Compat.Dates.TimeType prior to that.

Developer tips

One of the most important rules for Compat.jl is to avoid breaking user code whenever possible, especially on a released version.

Although the syntax used in the most recent Julia version is the preferred compat syntax, there are cases where this shouldn't be used. Examples include when the new syntax already has a different meaning on previous versions of Julia, or when functions are removed from Base Julia and the alternative cannot be easily implemented on previous versions. In such cases, possible solutions are forcing the new feature to be used with qualified name in Compat.jl (e.g. use Compat.<name>) or reimplementing the old features on a later Julia version.

If you're adding additional compatibility code to this package, the contrib/commit-name.sh script in the base Julia repository is useful for extracting the version number from a git commit SHA. For example, from the git repository of julia, run something like this:

bash $ contrib/commit-name.sh a378b60fe483130d0d30206deb8ba662e93944da

This prints a version number corresponding to the specified commit of the form X.Y.Z-aaa+NNNN, and you can then test whether Julia is at least this version by VERSION >= v"X.Y.Z-aaa+NNNN".

Tagging the correct minimum version of Compat

One of the most frequent problems package developers encounter is finding the right version of Compat to add to their REQUIRE. This is meant to be a guide on how to specify the right lower bound.

  • Find the appropriate fix needed for your package from the Compat README. Every function or feature added to Compat is documented in its README, so you are guaranteed to find it.

  • Navigate to the blame page of the README by clicking on the README file on GitHub, and then clicking on the blame button which can be found in the top-right corner.

  • Now find your fix, and then find the corresponding commit ID of that fix on the left-hand side. Click on the commit ID. This navigates to a page which recorded that particular commit.

  • On the top pane, you should find the list of the tagged versions of Compat that includes this fix. Find the minimum version from there.

  • Now specify the correct minimum version for Compat in your REQUIRE file by Compat <version>

First Commit


Last Touched

8 days ago


520 commits