I appreciate the intent, but man is this like a minefield waiting to be walked over. Anyone who looks at the code will scratch their head and will not understand what is going on. An annotation would perhaps make it clearer.
Also, how about IDE support? I would argue it is at least as important as the feature itself.
That is the generic argument against extension methods wherever they appear. They are very confusing, until you get used to remembering their existence, then you know what to search for.
Also, how about IDE support? I would argue it is at least as important as the feature itself.
This is mentioned in TFA.
"This looks odd to me so no one else can possibly understand it"is not a rigorous argument.
Both Scala and C# have this. I've used it in my own code to clean things up. It's fine.
"use strict";
from __future__ import annotations
{-# LANGUAGE TemplateHaskell #-}
which probably scales better than 2^n filename patterns.assertNotEmpty(getHttpContent(createSharedUrl(website, "styles.css")));
vs
website.createSharedUrl("styles.css").getHttpContent().assertNotEmpty();
Extensions are searchable by syntax and naturally in a namespace, largely diminishing the risk of put it in in a single use function that will be quickly forgotten, and might seem obscure.
The code itself might not be much shorter, but you don't introduce code looking weird, if it's re-usable it's now discoverable, and if your boilerplate contained a lot of micro adjustments on a larger glue code, this glue code is now shorter and way clearer.
The website examples aren't very inspiring indeed. Have a look at some of the extension functions for the Collections interface:
https://github.com/JetBrains/kotlin/blob/master/libraries/st...
I might want a nearly-Java language that only adds trivial syntax sugar, but are otherwise the same. Groovy sort of had a good initial idea here (being a superset of Java, though again, it has grown apart a bit since).
For me Kotlin lives in this weird limbo between these two extremes. If I want a different language on the JVM I would rather do Scala or Clojure.
extension (c: Circle)
def circumference: Double = c.radius * math.Pi * 2
val c = Circle(2, 3, 5)
c.circumference()If this is just to highlight the merit of static extension methods with a follow up JEP I am all for it, but please don't advertise this as a feature for production. It's a trap.
But tbh, there are some very good arguments against extension methods. Also, some tricky questions about overloading handling and compatibility are lurking in the shadow. But if you have good suggestions on how to fix them, I'd take the time to propose something on an OpenJDK mailing list, maybe you get some support.
So what you didn't notice is that you if you need to share SomeFunc across classes, you'd have to put it in a static class, so it's actually SomeStatic.SomeFunc(SomeObject) vs SomeObject.SomeFunc(). So you end up with a load of Utility classes with tons of static methods on them, or you do extensions.
But mostly the advantage is that it's actually clearer when you're reading the code.
It can also add quite a lot to discoverability in the right circumstances, not sure abut Java, but in C# you can include Extensions in global namespaces and so it just turns up in intellisense, without needing to know there's a special utility class.
Visual Studio has actually shipped new functionality recently where it will suggest extension methods (and classes) not included in your usings anyway, and then automatically add the using statements if you choose to use them. I thought this new functionality would annoy me but it's pretty clear from the prompt which objects are already in scope, and I only find myself occasionally having to clean up the using statements.
TL;DR; Looks a trivial change, but it surpisingly improves the readability of code, and the discoverability of home-grown utility functions.
SetReadTimeout(SetWriteTimeout(SetConnectTimeout(FactoryClass.factory(), 100), 2000), 4000);
vs. FactoryClass.factory().SetConnectTimeout(100).SetWriteTimeout(2000).SetReadTimeout(4000);
https://java-design-patterns.com/patterns/fluentinterface/ SetWriteTimeout(FactoryClass.factory().SetConnectTimeout(100), 2000).SetReadTimeout(4000);
Good luck correctly guessing the order of operations on that in a quick read...Better off transforming .java code at compile-time into .class'es in a .jar that always works at runtime.
In java, this would be a compile time problem, because once the class is compiled the extension method is called with `invokestatic` rather than `invokevirtual` used by class methods.
There is also a healthy fear of change in the java community that could explain it.
I think you can’t look at the past 5 years and the features that are being floated for Java 21 and future releases and think fear of change is the issue—the language is now changing rapidly.
There is also a healthy fear of change in the java community that could explain it.
Nice jab at the end! Java (well, really Sun, then Oracle) prioritises backwards compatibility over every other goal. So, does Win32 API. Does DotNet do the same? I'm unsure.This also explains why it took so long for Java to get lambdas. And, generics with primitive types, e.g., ArrayList<int>, via Project Valhalla. It is a super hard problem to upgrade Java without breaking old stuff. Hence, it is a multi-year R&D effort.
Using macros you can auto enable them for all types in a project, package, or module.
And opposite to Dart you don't need to define the extension methods in special extension classes but regular utility classes or modules.
website.createUrl("styles.css").getHttpContent(60).assertContains("img.jpg");
My preference would be: var stylesheet = http.get(website.resolve(“style.css”)).asString();
assertThat(stylesheet, contains(“img.jpg”));
Why? Fluent interfaces are good as internal DSL, where semantics of calls are clear and where readability is improved, because it looks closer to the natural language. This means that subject remains the same if you use multiple verbs. Just chaining several imperative statements does not add much value and only complicates debugging.What are you passing into http.get? a url, not something resolved.
As to whether they're worth the addition trouble or not, I sure as heck don't know.
But it's definitely nothing out of the ordinary.
blobs = createBlob()
.withinRange(min,max)
.excluding(a,b,c)
.asArray()
There are variations, for example where only the last call actually creates, say, a Blob array and where every intermediate call produces something only allowing the next method to be called, so that the IDE autocompletes nearly everything for you and where you won't be able to compile if you miss a single call.Don't know if the following link is any good but "fluent interfaces" are 15 years old stuff at least by now I'd say:
https://java-design-patterns.com/patterns/fluentinterface/#e...
Fluent will make you a more productive programmer, which may go against corporate policy.
Ha!
Anyway, nice work. Similar to D's uniform function call syntax.
https://tour.dlang.org/tour/en/gems/uniform-function-call-sy...
There's some more use cases in that link too.
With an extension method, I can do `object.` and my IDE will tell me what can be called on object. With a static helper method, it isn't as easy to know what is available. I need to know which helpers actually exist.
Since this doesn't have IDE support, it doesn't help discoverability. I'm not going to get nice autocomplete that shows me what is available. In fact, my IDE is going to highlight it as a bug. If I have a spelling mistake, I won't be able to easily pick it up - I'll assume it's just the normal complaint for all of these fluent extension methods.
That makes this simply syntactic sugar rather than something that actually helps me discover things more easily. It then hurts readability and navigation since I can't easily click through to get the definition of the method.
On a more general note about Java, things like this are one of the reasons I don't love the Java ecosystem. People try to change the behavior of Java in really hacky ways that don't work well. I understand that it's an attempt to overcome shortcomings in the language, but when one looks other languages it becomes clear that Java could have just evolved the language to be better. Java has lots of good things and I'm not looking to argue that. However, when I look at things like this, it makes me think that Java needs to really address the core language.
Instead, we get lots of tools like this which might be nice, but make it really hard to understand what's going on. Electronic Arts created an async/await library that'll do crazy stuff to let you do async/await style programming (https://github.com/electronicarts/ea-async). Yes, Java is doing good things with structured concurrency and Project Loom, but the point is how people keep trying to work around the language. There are so many POJO generators it isn't funny: AutoValue, Immutables, JodaBeans, Lombok, and more I'm probably forgetting. Java records don't fulfill everything (and they're at least a decade late). Java doesn't support expression trees for lambdas so libraries sometimes do crazy hacky things to make that exist.
Java is a great piece of technology, but it feels like people are often trying to overcome issues with the language through really hacky means in a way that I don't see in other languages. Java is getting better about modernizing the language, but it still feels like people are running against the language more than in other ecosystems.
This really isn't solving any real problems either. The first set of syntax shows definitive programmer intent at the cost of.... 4 extra keyboard presses. The code will also fail compilation or even at runtime if some API changes in a dependency, which is a _good thing_.
If you want extension methods on the JVM, do yourself a favor and pick kotlin.
I know I know, stuff like this exists for when corporate policy insists on sticking with java, but a corporate policy that at the same time rejects kotlin but allows bastardizing java like this it's a broken corporate policy. The good news however is that stuff like this can be an excellent tool to put pressure on that kind of policy ("if we don't get to use the good stuff we'll use the bad stuff!") and if it was made for that use case, I'll wholeheartedly applaude.
That being said, I'd really, really love to see the kotlin treatment applied to other languages, stuff that doesn't have actual kotlin waiting on the sidelines. Once I got used to the ease of left-to-right provided by kotlin context method funnels it's really painful to go back to nested if blocks (even in languages like typescript that apply the type inference of the conditional to the nested block just fine).
static URL buildSiteURL() {
Website website = getMyWebSite();
String path = "styles.css";
return createUrl(...);
}Need to see some benchmarks for this, chief.
Still, cool hack, and it's heartening to see that there's enough extensibility to make this possible in 150 lines of code!
i appreciate that using an ide makes code navigation easier but i reject the notion that you should need one to navigate the code