-
Notifications
You must be signed in to change notification settings - Fork 155
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
Functions backwards compatibility #274
Comments
Nit: this is actually not the case currently, because the function name in the plan must include "opt" for each optional enum argument, and optional arguments actually have to be explicitly set to "unspecified" in the plan. (I think I didn't understand this yet back when we had this sync meeting) For your proposal, it sounds a bit like you're reinventing semver. Why not just go the extra mile and use x.y.z versions for each function? |
Can you give an example of what would constitute a minor change or a patch change? I think I was basically arguing that there is no way to do either so we shouldn't bother with those. |
Sure;
|
TL:DR; Thanks. I will concede that semver would be better. The one point I disagree on is that I think adding/removing implementations should not affect function versioning. Otherwise what will happen when new implementations are added for extension types to existing functions?
I had been thinking purely of producers & consumers. None of these changes would be something they care about (since producers and consumers don't really need the YAML). If a consumer works with version 1.2.3 and version 1.2.4 fixes a description typo then there would be zero reason to upgrade the consumer. However, this logic doesn't apply for validators, visualizers, etc. In those cases the YAML is often presented to the end user (e.g. in a validator error message or visualizer display) and so it makes sense users would want the latest version installed.
Very good example I had not thought of.
In my mind implementations were kind of independent things so adding an implementation would be going from version 0 (does not exist) to whatever the version of the function you are adding is. So there would be no need to raise the version in this case.
This is an incredibly subtle and beautiful example. I hope you at least had to wrack your brain for a while to come up with it. I agree.
Again, I'm not sure I agree that function versioning should be bound to implementations. |
You lost me with these statements. I think I may be making incorrect assumptions about where these version numbers are and what they are associated with. My assumption was that a function (i.e. at the name + description + implementation list level) gets a version number, and that a function extension declaration in the plan would include a version number that the actual function version must be compatible with, but now that I'm thinking about it more thoroughly I'm not sure how that would work with the URIs. Can you explain where you think the version numbers should be?
Coincidentally I had given a very extensive explanation about how those nullability things work and what the edge cases are to Phillip a few hours prior, so it was fresh in my mind :) |
My thinking was that it would not include implementations (e.g. at the same level as name + description). One approach could be in both the YAML and the protobuf:
Another approach could be in the name (which conveniently, wouldn't require a protobuf change):
From a consumer perspective the "in the name" approach was going to be automatic if we were just doing a single version number ("add-2" is simply a different function, no one needs to know the "-2" part represents the version). No parsing of the version would be required. Unfortunately, this does not really work as conveniently if we are going to consider patch versions (since "add-1.0.0" and "add-1.0.1" will map to the same function implementation). So in that case I would prefer the first, more explicit, approach. I'm not certain it makes sense to version the implementation. Either an implementation exists for the function/version pair or it doesn't. Adding a new implementation does not require a version change nor does dropping an implementation. For example, if I want to query a consumer to know what functions/implementations it supports I would not say "Do you support add-1.0.0?" and expect "yes" to mean that the consumer supports all implementations. Instead I would say "List the supported implementations for add-1.0.0" and then inspect the list. |
Okay, I think I now understand what you mean. My gut feeling was to disagree and argue in favor of "Do you support add-1.0.0? -> y/n", but I guess you have a point; if a hypothetical consumer just doesn't support i64 at all for whatever reason, it would never be able to satisfy any of the core arithmetic functions (as currently defined) by that logic. It's still conceptually very counter-intuitive to me to slap a version number on a list of things and then be able to manipulate that list (by adding to or removing from it in this case) without requiring a different version. IMO, these versions should not exclusively be a tool for a producer to determine whether it needs to do some casting before calling a function in order to be compatible, but also for people to see "has something changed," or for other things we just haven't thought of yet. Imagine a documentation tool for instance that uses these versions to determine whether it needs to regenerate something; clearly it does if an implementation is removed or added. But I see your point -- a consumer may reasonably only implement a subset of a function's implementations -- and would personally address it by giving each implementation a version number rather than versioning a function name. In fact, I'd argue that these function names are weird to begin with. I'm struggling to even come up with a word for them. Shouldn't they just be separate functions for all intents and purposes, except for that we silly humans conceptualize them as doing roughly the same thing? That's how C handles overloads, anyway, and also kind of how Substrait does it, considering how compound names work. So I would want to avoid attaching more meaning to a group of implementations with the same name than... a group of implementations that happen to have the same name because it makes sense to humans. When it comes to more intelligently dealing with a "no" response to "would you be compatible with the query I've concocted?" than just propagating the error onto the user, such as promoting argument types to get to an implementation that does exist, I don't think it's currently safe to assume that the function would still behave the same after the upcast just because they have the same name. You pointed that out yourself during the sync meeting after all. I'm just piping my thoughts straight to github at this point, but what would you think of a scheme like this:
In this scheme we don't need complex versioning because, rather than hiding it behind a version number, we just query all machine-readable information straight from the consumer. We only need a version number for the more "human" description of functionality, in conjunction with the function name. I actually wonder if we should bother with version numbers at all in this case; maybe we should just say that if we correct a description along the lines of "1 + 1 is not in fact 3 but 2" we should just call the function As for |
I think this is useful discussion but I don't think there is any enthusiasm for acting on this. At the end of the day I suspect we will be able to get by with versioned names (e.g. So I am going to close this issue but if anyone wants to return to this discussion and make a new proposal they are welcome to do so. |
Background:
A few community syncs back we discussed backwards compatibility for functions (e.g. yaml elements) at some length. I'd like to capture some of the key thoughts here:
We also discussed potentially versioning the URIs for functions:
Finally, there was discussion about marking a function as "stable" / "sealed":
Proposal:
The text was updated successfully, but these errors were encountered: