-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decoupling interface versioning and Tables.jl API versioning? #133
Comments
Hmmmm........at first glance, I'm worried about the complexity here. For example, most provider packages are also consumer packages, i.e. they provide a table source as well as a sink function to take any tables source and "consume" the table into its own format, so it's not entirely clear that the strategy would still work for them. I think I'm also failing to see the motivation here, or what problem this solves? It seems like regular sem-versioning does the job; if we make breaking or mandatory new API changes, then we bump the major version, and everything continues to work until packages upgrade and support the new stuff (like we're currently planning for the 1.0 release). |
The motivation is for automating interface compatibility test. This, in turn, requires a way to find out what interface is supported by a given type. For example, let's say you'd want to add a sink-oriented API at v1.1 Tables.into(DestType::Type, src) => DestType You can then create an automated test like this: module Table
...
function test(m::Module, table)
...
if api_version_of(m) >= v"1.1"
@testset "into" begin
DestType = typeof(table)
for src in sample_tables_for_test()
dest = into(DestType, src)
@test dest isa DestType
@test collect(rows(dest)) == collect(rows(src))
end
end
end
...
end
...
end However, unless Tables.jl versioning is decoupled from the "interface versioning" (i.e., without |
Here's how I would imagine a setup just relying on semver working:
Then hypothetical
CSV.jl reviews the new API and implements
Is there a bad case in these scenarios? Does it cause problems at all? In my mind, TablesTests.jl has always been a separate package that would keep up/compat with Tables.jl. |
An alternative strategy that wouldn't require packages with Tables.j dependencies to have compat like This is very good discussion to have now though as we prepare for a 1.0 release so it's very clear our policy/strategy going forward. I'll make an action item from this issue to do a writeup in the docs about the Tables.jl release policy/process. |
I think the most important aspect of SemVer is backward compatibility. I think using (And I think this is why we need a bit of trick here. Provider packages have to talk about (a lack of) forward compatibility.)
I agree this is a good strategy that requires less hustle, provided that the interface are going to be changed very slowly. Having said that, I think the disadvantages of the major version approach compared to TablesAPI.jl are:
My assumption is that adding new interfaces would be more frequent than breaking existing APIs and consumer packages are the majority. That's why I thought it makes sense to decouple the "basic" interface versioning from Tables.jl (major) versioning. This way, consumer packages do not receive false alarms via the major bumps of Tables.jl that might indicate inclusion of the new "basic" interface (that they couldn't possibly have been using)
I agree this is a good approach. I wanted to avoid introducing more concepts in the OP so I was using |
It might be nice to have a way to decouple Tables.jl implementation and interface versions. Packages providing generic table processing functions may want to impose availability of certain table interfaces and/or availability of certain utility functions ("secondary" APIs) provided by Tables.jl. Being able to declare these different notions of compatibility separately makes sense. I think this makes growing Tables.jl interface easier and safer.
I think one way to do this might be to prepare an empty package (say)
TablesAPI
and a single functionTables.test(mytable)
(ref #131 (comment)). Alternatively, the packageTablesAPI
may contain empty/trivial function definitions, likeDataAPI
. Packages with custom table types (provider packages) can then declare its interface-compatibility bywhile invoking something like
from their test suite. This way, interface version compatibility would be enforced by the test suite.
(Detail: since the dependencies of
ProviderPackage
may upper-bound the version ofTablesAPI
, we need to make sure thatTablesAPI
used in the test is the latest version thatProject.toml
ofProviderPackage
claims. This is why the moduleProviderPackage
is passed as the argument ofTables.test
. This function then can parseProject.toml
ofProviderPackage
andTablesAPI
and check the versions.)On the other hand, packages that consumes table interfaces declare usual lower bound for
TablesAPI
:This way, users can safely assume that all packages within an environment satisfy given Tables interface.
To clarify the difference:
Tables.rows
support for more types inBase
.Of course, this scheme could be too strict. You may be using the part of
ConsumerPackage
that requires onlyTablesAPI
v1.0. In that case, it'd be annoying ifYetAnotherProviderPackage
declaresTablesAPI = "< 1.1"
. However, my guess is that this is not a problem because I'd imagineTablesAPI
is updated very slowly (maybe less than once a year).The text was updated successfully, but these errors were encountered: