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.Stringand 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.
Currently, the @compat macro supports the following syntaxes:
-
@compat foo.:bar—foo.(:bar)in 0.4 (#15032) -
@compat f.(args...)—broadcast(f, args...)in 0.4 (#15032) -
@compat (a::B{T}){T}(c) = d— the Julia 0.5-style call overload -
@compat(get(io, s, false)), withsequal to:limit,:compactor:multiline, to detect the corresponding print settings (performs useful work only on Julia 0.5, defaults tofalseotherwise) -
@compat import Base.showand@compat function show(args...)for handling the deprecation ofwritemimein Julia 0.5 (#16563). See #219. -
@compat @boundscheck checkbounds(...)rewrites to unconditionally callcheckbounds(...)in 0.4. The 0.4-style two-argument form of@boundscheckis left unchanged. -
@compat Nullable(value, hasvalue)to handle the switch from theNullable:isnullfield to:hasvaluefield (#18510) -
@compat x .= yconverts to an in-place assignment tox(viabroadcast!) (#17510). However, beware that.=in Julia 0.4 has the precedence of==, not of assignment=, so if the right-hand-sideyincludes expressions with lower precedence than==you should enclose it in parenthesesx .= (y)to ensure the correct order of evaluation. Also,x .+= yconverts tox .= (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.4 and 0.5, this only works for non-nested usages (e.g. you can't defineArray{<:Array{<:Real}}). -
@compat abstract type T endand@compat primitive type T 8 endto declare abstract and primitive types. #20418 This only works when@compatis 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. Useconst A = Bfor type alias without free parameters. -
@compat Base.IndexStyle(::Type{<:MyArray}) = IndexLinear()and@compat Base.IndexStyle(::Type{<:MyArray}) = IndexCartesian()to define traits for abstract arrays, replacing the formerBase.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearFast()andBase.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearSlow(), respectively.
-
In 0.6, some 0.5 iterator functions have been moved to the
Base.Iteratorsmodule. Code can be written to work on both 0.5 and 0.6 byimporting orusingtheCompat.Iteratorsmodule instead. (#18839) -
The
Compat.Iteratorsmodule is also available on 0.4, including the iterator functionspartition,product, andflatten, which were introduced in Julia 0.5. However, because of a variety of other changes to the iterator system between 0.4 and 0.5, these functions behave slightly differently. For example, theIterators.productfunction on 0.4 does not return objects with shapes. (#14596, #14805, #15409)
-
In 0.5,
ASCIIStringandByteStringwere deprecated, andUTF8Stringwas renamed to the (now concrete) typeString.Compat provides unexported
Compat.UTF8StringandCompat.ASCIIStringtype aliases which are equivalent to the same types from Base on Julia 0.4, but toStringon Julia 0.5. In most cases, using these types by callingimport Compat: UTF8String, ASCIIStringshould be enough. Note thatCompat.ASCIIStringdoes not guarantee that the string only contains ASCII characters on Julia 0.5: callisasciito check if the string is pure ASCII if needed.Compat also provides an unexported
Compat.Stringtype which is equivalent toByteStringon Julia 0.4, and toStringon Julia 0.5. This type should be used only in places whereByteStringwas used on Julia 0.4, i.e. where eitherASCIIStringorUTF8Stringshould be accepted. It should not be used as the default type for variables or fields holding strings, as it introduces type-instability in Julia 0.4: useCompat.UTF8StringorCompat.ASCIIStringinstead. -
bytestringhas been replaced in most cases with additionalStringconstruction methods; for 0.4 compatibility, the usage involves replacingbytestring(args...)withCompat.String(args...). However, for converting aPtr{UInt8}to a string, use the newunsafe_string(...)method to make a copy orunsafe_wrap(String, ...)to avoid a copy.
-
@viewstakes 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@compatmacros. -
foreach, similar tomapbut when the return value is not needed (#13744) -
walkdir, returns an iterator that walks the directory tree of a directory (#13707) -
allunique, checks whether all elements in an iterable appear only once (#15914) -
Base.promote_eltype_opis available asCompat.promote_eltype_op -
normalizeandnormalize!, normalizes a vector with respect to the p-norm (#13681) -
redirect_stdout,redirect_stderr, andredirect_stdintake an optional function as a first argument,redirect_std*(f, stream), so that one may usedoblock syntax (as first available for Julia 0.6) -
unsafe_getreturns the:valuefield of aNullableobject without any null-check and has a generic fallback for non-Nullableargument (#18484) -
isnullhas a generic fallback for non-Nullableargument -
transcodeconverts between UTF-xx string encodings in Julia 0.5 (as a lightweight alternative to the LegacyStrings package) (#17323) -
∘(typically used infix asf ∘ g) for function composition can be used in 0.5 and earlier (#17155) -
>:, a supertype operator for symmetry withissubtype(A >: Bis equivalent toB <: 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 whetherx == zero(x)(including arrays) can be used in 0.5 and earlier (#19950). -
.&and.|are short syntax forbroadcast(&, xs...)andbroadcast(|, xs...)(respectively) in Julia 0.6 (only supported on Julia 0.5 and above) (#17623) -
Compat.isapproxwithnanskeyword argument (#20022) -
Compat.readlinewithchompkeyword argument (#20203) -
take!method forTasks since some functions now returnChannels instead ofTasks (#19841) -
The
isabstract,parameter_upper_bound,typenamereflection methods were added in Julia 0.6. This package re-exports these from theCompat.TypeUtilssubmodule. On earlier versions of julia, that module contains the same functions, but operating on the pre-0.6 type system representation. -
broadcastis supported on tuples of the same lengths on 0.5. (#16986) -
zerosandonessupport an interface the same assimilar(#19635) -
convertcan convert between differentSettypes 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) -
bswapis supported forComplexarguments on 0.5 and below. (#21346) -
Compat.StringVectoris supported on 0.5 and below. On 0.6 and later, it aliasesBase.StringVector. This function allocates aVector{UInt8}whose data can be made into aStringin constant time; that is, without copying. On 0.5 and later, useString(...)with the vector allocated byStringVectoras an argument to create a string without copying. Note that if 0.4 support is needed,Compat.UTF8String(...)should be used instead. ([#19449])
-
pointer_to_arrayandpointer_to_stringhave been replaced withunsafe_wrap(Array, ...)andunsafe_wrap(String, ...)respectively -
bytestring(::Ptr, ...)has been replaced withunsafe_string -
superis nowsupertype(#14338) -
qr(A, pivot=b)is nowqr(A, Val{b}), likewise forqrfactandqrfact! -
readallandreadbytesare nowreadstringandread(#14660) -
get_bigfloat_precisionis nowprecision(BigFloat),set_precisionissetprecisionandwith_bigfloat_precisionis now alsosetprecision(#13232) -
get_roundingis nowrounding.set_roundingandwith_roundingare nowsetrounding(#13232) -
Base.tty_size(which was not exported) is nowdisplaysizein Julia 0.5 -
Compat.LinAlg.checksquare(#14601) -
issymis nowissymmetric(#15192) -
istextis nowistextmime(#15708) -
symbolis nowSymbol(#16154) -
write(::IO, ::Ptr, len)is nowunsafe_write(#14766) -
sliceis nowview(#16972); doimport Compat.viewand then useviewnormally without the@compatmacro -
fieldoffsetshas been deprecated in favor offieldoffset(#14777) -
print_escapedis now another method ofescape_string,print_unescapeda method ofunescape_string, andprint_joineda method ofjoin(#16603) -
writemimehas been merged intoshow(#16563). Note that to extend this function requires@compat; see the Supported Syntax section for more information -
$is nowxoror⊻(#18977) -
numanddenare nownumeratoranddenominator(#19246) -
takebuf_arrayis now a method oftake!.takebuf_string(io)becomesString(take!(io))(#19088)
-
@statichas been added (#16219) -
@functorize(not present in any Julia version) takes a function (or operator) and turns it into a functor object if one is available in the used Julia version. E.g. something likemapreduce(Base.AbsFun(), Base.MulFun(), x)can now be written asmapreduce(@functorize(abs), @functorize(*), x), andf(::Base.AbsFun())asf(::typeof(@functorize(abs))), to work across different Julia versions.Func{1}can be written assupertype(typeof(@functorize(abs)))(and so on forFunc{2}), which will fall back toFunctionon Julia 0.5. -
Compat.@blasfuncmakes functionality ofBase.LinAlg.BLAS.@blasfuncavailable on older Julia versions -
@__DIR__has been added (#18380) -
@vectorize_1argand@vectorize_2argare deprecated on Julia 0.6 in favor of the broadcast syntax (#17302).Compat.@dep_vectorize_1argandCompat.@dep_vectorize_2argare 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.6is dropped fromCompat.
-
remotecall,remotecall_fetch,remotecall_wait, andremote_dohave the function to be executed remotely as the first argument in Julia 0.5. LoadingCompatdefines the same methods in older versions of Julia (#13338) -
Base.FSis nowBase.Filesystem(#12819) Compat provides an unexportedCompat.Filesystemmodule that is aliased toBase.FSon Julia 0.4 andBase.Filesystemon Julia 0.5. -
covandcordon't allow keyword arguments anymore. Loading Compat defines compatibility methods for the new API (#13465) -
On versions of Julia that do not contain a Base.Threads module, Compat defines a Threads module containing a no-op
@threadsmacro. -
Base.SingleAsyncWorkis nowBase.AsyncConditionCompat provides an unexportedCompat.AsyncConditiontype that is aliased toBase.SingleAsyncWorkon Julia 0.4 andBase.AsyncConditionon Julia 0.5. -
repeatnow accepts anyAbstractArray(#14082):Compat.repeatsupports this new API on Julia 0.4, and callsBase.repeaton 0.5. -
OS_NAMEis nowSys.KERNEL. OS information available asis_apple,is_bsd,is_linux,is_unix, andis_windows(#16219) -
cholfact,cholfact!, andcholrequire that input is eitherHermitian,Symmetricor that the elements are perfectly symmetric or Hermitian on 0.5. Compat now defines methods forHermOrSymsuch that using the new methods are backward compatible. -
Diagonaland*methods supportSubArrays even on 0.4. -
Single-argument
min,maxandminmaxare defined on 0.4.
Currently, no new exported types are introduced by Compat.
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
0.5.0-dev+2023This 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".
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
CompatREADME. Every function or feature added toCompatis 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
blamebutton 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>