Skip to content
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

Deprecation of last in Xtend #3187

Open
dpetroff opened this issue Sep 6, 2024 · 3 comments
Open

Deprecation of last in Xtend #3187

dpetroff opened this issue Sep 6, 2024 · 3 comments

Comments

@dpetroff
Copy link

dpetroff commented Sep 6, 2024

I'm concerned that I couldn't find any discussion related to the commit here, and from my perspective as an Xtend user, this seems to make very little sense.

From the perspective of Xbase, I would not have thought that changing the semantics of Xbase libraries makes sense just because Java adds a method to List with a similar but actually different name (note the get part in the Java version) and different semantics. I may be wrong since it was a while since I've used Xbase directly, but my understanding is that, in Xbase, extensions are opt-in and the extensions part of the Xbase library is provided as a convenience for language developers. In this case, it ought to be up to individual language implementers to choose how they deal with Java introducing breaking semantics.

From the perspective of Xtend, the language is called Xtend, it's all about extensions as a core concept, and it never made sense to me that extension methods do not override object methods of the same name. I made peace with the last part because I can see how a breaking change that kills every Xtend project ever is not going to take place lightly.

Yet here we are, deprecating last because Java is unintentionally introducing this kind of a breaking change that I expected would never come from Xtend. Replacing last with lastOrNull is not appropriate because the semantics of Xbase and Xtend iterables have always been that they do not throw exceptions. I can see how throwing the exception is technically correct and will cover the 0.5% of corner cases where that actually matters, but the semantics of last are already very nice

I propose instead of accepting the breaking change coming from Java and deprecating last we pick one of the following better options:

  1. Commit to Xtend extension libraries taking precedence over "real" member methods. This has a small chance of introducing bugs in existing code, but not any more significant than the potential of Java introducing more breaking changes just like this one in the future. The benefit is that Java will never have the chance to break Xtend code again, while the potential for breaking existing code is limited. I think as a one-time breaking change that will remove the potential for future breaking changes, this is acceptable. There could be a compiler preference such that existing projects have to opt-in and remain entirely unaffected but new Xtend projects would have the new future-proof semantics.
  2. Really commit to Xtend being about extensions, hard. Like above but applies to all extension methods, imports, and providers as well. Very breaking. But also very satisfying. Could be similarly opt-in for existing code. I suppose even 1. vs 2. may be a setting with 1. being the default for new projects and 2. being available as an option for the die-hard extension fans such as myself.
  3. Some sort of middle ground where last is preferred because the member method in Java is called getLast and can therefore be explicitly referenced. This is by far the worst option because it relies on naming convention to avoid future intrusions from Java member methods. But it has the benefit of actually not breaking any existing code, so I figured it was worth mentioning.

I submit for your consideration that as an Xtend user for nearly a decade, I find that there is realistically no use case for defining an extension method with the same name as a member method where the member method is preferred over the extension method. In my experience, the bugs have always come from forgetting that a member method already exists and expecting my extension method to be used instead. However, I propose that if the need seems significant, the self keyword may be reused to explicitly access member methods such as someThing.self.memberMethod when it's necessary, as unlikely as they may seem to me.

@dpetroff
Copy link
Author

dpetroff commented Sep 6, 2024

I would be interested in contributing some solution along the lines of 1. or 2. myself, though I can't say when I might have time to do such a thing, and I'll definitely need some help setting up. The last time I considered contributing something to the project some years ago, I was immediately put off because there were many errors in the various projects after oomph finished setting up the workspace and the instructions did not seem to expect this outcome.

@LorenzoBettini
Copy link
Contributor

@dpetroff I personally handled the issue about last. Its deprecation was highly discussed in the corresponding issue and PR. It was also well-documented in the corresponding release note.

At the beginning, I was suggesting something along with what you propose. @szarnekow suggested instead to keep things simpler. Note that, if I'm not wrong, the precedence that was implemented long ago to new Java methods like forEach prefers the Java version to the extension method.

In this case, single last is specified in the program, maybe the syntax sugar for getLast could be avoided. However, I don't know how complex would that be.

@szarnekow
Copy link
Contributor

It's a curious case. One of the design principles was and is that neither Xbase nor Xtend will disallow accessing members that would be accessible the same way from Java. In that sense, an extension method must never shadow a member. This principle won't change since it will likely break many existing programs.
Also note that the shadowing semantics with the property access, extension methods, static extension methods, enclosing classes, var args, etc., are already very complex, and special casing something for last or getLast does not add any value for the uninitiated user.
In the end, it's inevitable for a library to potentially conflict with APIs added in the JDK. We need to accept that and embrace the progress made for Java itself. If that includes marking an API as deprecated and encouraging users to migrate to another method with a refined name, I'd always make the same decision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants