Is Compat.jl worth it for the `public` keyword?

With the introduction of public by @Lilith, many packages will want to mark their unexported public symbols that way. Since public is only available in Julia 1.11, the current recommended way to do this in 1.10 is with the Compat.jl package. Before we add it everywhere, I’m wondering if there are any negative side effects to it? @stevengj seems to think it’s fine but I’d love to get other opinions.

In particular, it depends on 4 stdlibs: Dates, LinearAlgebra, TOML and UUIDs.

1 Like

If you don’t already depend on Compat.jl, I’d recommend

VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("public foo, bar"))
6 Likes

If it’s such a minimal change, why is there no motivation to add this no-op to v.1.10?
Because it’s a dirty hack?

1 Like

Because features are not backported in semver. There’s a rather extensive discussion here:

7 Likes

Is there a way to combine this trick with multiple lines of public declarations?

I get a ParseError on 1.11.0-rc3 when trying

VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("begin
    public foo
    public bar
end"))

@static VERSION >= v"1.11" && eval(Meta.parse("""include("public.jl")"""))

I’ve tried this a while ago without eval, generally it worked but had some side effects (not in the code execution, I can’t remember exactly what), and I switched to Compat.jl after the opinion by stevengj.

P.S. Discourse makes 2 lines of code out of 1 source line because of &&

Why not this then?

@static if VERSION >= v"1.11"
    include("public.jl")
end

This should be sufficient:

VERSION >= v"1.11" && include("public.jl")

@static partially evaluates expressions at macro-expansion time which is only useful if macro expansion is invalid on a previous version. include macro expands just fine on all versions so there’s no need for @static.

9 Likes

That’s exactly what I did and now can’t remember what was wrong, but there was something (Documenter.jl, CI, something like that).

Could’ve been CoverageTools? I had something like it here

1 Like

I guess most important is if the tooling that can benefit from that will support any of the alternative ways to declare public in 1.10.

1 Like

Well possible.

VERSION >= v"1.11" && eval(Meta.parse("""include("public.julia")"""))

That would probably guarantee there are no CI side effects.

There is also the (proposed, but rejected) GitHub - JuliaLang/Public.jl

That seems small enough so that it could simply be vendored by projects that do not want to use Compat

1 Like

To ask if something is “worth it” you need to ask about weight on the other side of the scale. What are we talking about here? Maybe a second worth of precompile time, once? Even less? Its four dependences are all (still) old-style stdlibs baked into Julia’s default sysimage, no?

5 Likes

JuliaSyntax.jl is a new stdlib in 1.10. It defines the new keyword public and people want workarounds to work with 1.10 LTS, for package code, though most likely some packages will get left out.

It already has an option JULIA_USE_FLISP_PARSER to 1

It could add JULIA_ADD_PUBLIC_KEYWORD env var, off by default, for “compatibilty”/semver reasons. I would rather want it the other way though.

Some stdlibs are upgradable, not sure about that one…

Can the dependencies of Compat.jl get turned into weak dependencies through package extensions? I see that was already started with LinearAlgebra: move LinearAlgebra and Dates to package extensions by oscardssmith · Pull Request #790 · JuliaLang/Compat.jl · GitHub (EDIT: though for some reason LinearAlgebra is still listed as a dependency…).

1 Like

When 1.11 comes out, why should packages try and support 1.10? If they want to use a feature in 1.11 why not just keep things simple and set julia compat to 1.11. In my experience adding any nonessential dependencies or weak dependencies quickly leads to dependency hell when working on a complex Julia code base.

If one doesn’t want to use Meta.parse, one can say

VERSION >= v"1.11.0-DEV.469" && eval(Expr(:public, :foo, :bar))
1 Like

LTS

Maybe a tiny (pre)compilation time, which you can just benchmark if you are worried about it.

The benefits (cleaner, easier to maintain code) easily outweigh it IMO.