I searched, and it doesn’t look like anyone has asked this before, but I would be surprised if I am the first, so I apologize if this question is a dupe and I missed it.
In the newly released Julia v1.8.0, you can annotate a field of a mutable struct with const like so:
julia> mutable struct Smile
const curvature::Float64
end
In 1.6.7, this is a syntax error:
julia> mutable struct Smile
const curvature::Float64
end
ERROR: syntax: expected assignment after "const"
Stacktrace:
[1] top-level scope
@ none:1
Is there a way to define Smile so that if the version is < 1.8.0, it is just a struct, and if the version is ≥ 1.8.0, it is a mutable struct with const curvature?
Would it be wise to do so?
Note that the following fails in 1.6.7:
julia> if VERSION >= v"1.8.0"
mutable struct Smile
const curvature::Float64
end
else
struct Smile
curvature::Float64
end
end
ERROR: syntax: expected assignment after "const"
Stacktrace:
[1] top-level scope
@ none:1
To give a little more context, users of my package[1] are currently used to Smile being an (immutable) struct, and now I want to give them the option of mutating some (but not all) of the fields of Smile. But I also want to maintain compatibility with the LTS branch, with the understanding that the mutation functionality will only be available if you use v1.8.0 or higher.
So, I’m not trying to turn a mutable struct into a mutable struct with const fields, which would be a breaking change (because users of the package may have written code that mutates a field that is now going to become immutable). Rather, I’m trying to change a struct into a mutable struct.
julia> @static if VERSION >= v"1.8.0"
mutable struct Smile
const curvature::Float64
end
else
struct Smile
curvature::Float64
end
end
ERROR: syntax: expected assignment after "const"
Stacktrace:
[1] top-level scope
@ none:1
macro _const(expr)
if VERSION >= v"1.8.0-"
Expr(:const, esc(expr))
else
esc(expr)
end
end
In v1.7:
julia> mutable struct Foo
@_const x
end
In v1.8:
julia> mutable struct Foo
@_const x
end
julia> isconst(Foo, :x)
true
Edit: sorry, I missed that you want a struct in v1.7 and below, rather than a mutable struct. So the answer here doesn’t quite work, but at least it shows how you can actually generate code with const in it only on v1.8.
You could put the 1.6-compatible struct definition in one source code file, and put the 1.8-compatible struct definition in another file. And then your package would have code of the form:
if VERSION >= v"1.8"
include("structs-1.8.jl")
else
include("structs-1.6.jl")
end
@rdeits No worries, it’s clear how you could use the same approach on the mutable keyword.
@dilumaluthge This is an elegant solution, with the small downside that you have to repeat all the docstrings, inner constructor methods etc. in each file.
I wonder if there’s a way to have everything in the same file, though? I was surprised that the following doesn’t work, since the documentation says that you can use a begin ... end block with @eval:
if VERSION >= v"1.8.0"
@eval begin
mutable struct Smile
const curvature::Float64
end
end
else
@eval begin
struct Smile
curvature::Float64
end
end
end
Presumably, each file would only contain the functionality that is different between the versions, and the rest of the code would be in a common, third file.
The docstring doesn’t need to appear in each file, as you may add it to the struct name instead of the definition. As an example:
julia> begin
"""
A
Struct `A`, wraps an `Int`
"""
A
struct A
x :: Int
end
end
help?> A
search: A Any any all abs ARGS ans axes atan asin asec any! all! acsc acot acos abs2 Array atanh atand asinh asind asech asecd ascii angle acsch acscd acoth
A
Struct A, wraps an Int
julia> A(2)
A(2)
Regarding the inner constructors, if these are identical across versions, perhaps you’ll need a third file that you include within each struct definition
Unfortunately, even this doesn’t seem to work completely, e.g in this PR, where tests pass on v1.6, but the coverage run fails with the same error. Is there a way to instruct the coverage action to ignore certain files on specific versions?