41

I am looking for a java equivalent to the C# extension methods feature. Now I have been reading about Java 8's default methods, but as far as I can see, I can only add these to interfaces...

...is there any language feature that will allow me to write an extension method for a final class that doesn't implement an interface? (I'd rather not have to wrap it...)

Cheetah
  • 13,785
  • 31
  • 106
  • 190
  • 1
    [Manifold](http://manifold.systems/) provides comprehensive C#-style extension method support for Java. Learn more: [http://manifold.systems/docs.html](http://manifold.systems/docs.html) [https://github.com/manifold-systems/manifold](https://github.com/manifold-systems/manifold) – Scott Apr 12 '18 at 19:56
  • Maybe now you can use Kotlin extensions as an alternative, https://kotlinlang.org/docs/reference/extensions.html – nsafari Apr 07 '20 at 10:21

5 Answers5

31

Java doesn't have extension methods. Default methods are not extension methods. Let's look at each feature.

Default methods

Both Java and C# support this feature

Problems solved:

  1. Many objects may implement the same interface and all of them may use the same implementation for a method. A base class could solve this issue but only if the interface implementors don't already have a base class as neither java nor C# support multiple inheritance.
  2. An API would like to add a method to an interface without breaking the API consumers. Adding a method with a default implementation solves this.

Java's or C#'s default methods are a feature to add a default implementation to an interface. So objects that extend an interface don't have to implement the method, they could just use the default method.

interface IA { default public int AddOne(int i) { return i + 1; } }

Any object that implements IA doesn't have to implement AddOne because there is a default method that would be used.

public class MyClass implements IA { /* No AddOne implementation needed */ } 

C# now has this feature in C# 8 (or .Net 5)

C#'s Extension Method

Problems solved:

  1. Ability to add methods to sealed classes.
  2. Ability to add methods to classes from third-party libraries without forcing inheritance.
  3. Ability to add methods to model classes in environments where methods in model classes are not allowed for convention reasons.
  4. The ability for IntelliSense to present these methods to you.

Example: The type string is a sealed class in C#. You cannot inherit from string as it is sealed. But you can add methods you can call from a string.

var a = "mystring";
a.MyExtensionMethed()

Java lacks this feature and would be greatly improved by adding this feature.

Conclusion

There is nothing even similar about Java's default methods and C#'s extension method features. They are completely different and solve completely different problems.

Rhyous
  • 6,510
  • 2
  • 44
  • 50
  • 1
    In C# 8, Default Methods in interfaces will exist. https://channel9.msdn.com/Blogs/Seth-Juarez/A-Preview-of-C-8-with-Mads-Torgersen#time=26m13s – Rhyous Dec 13 '17 at 15:19
24

C# extension methods are static and use-site, whereas Java's default methods are virtual and declaration-site.

What I believe you are hoping for is the ability to "monkey-patch" a method into a class you do not control, but Java does not give you that (by design; it was considered and rejected.)

Another benefit of default methods over the C# approach is that they are reflectively discoverable, and in fact from the outside, don't look any different from "regular" interface methods.

One advantage of C#'s extension methods over Java's default methods is that with C#'s reified generics, extension methods are injected into types, not classes, so you can inject a sum() method into List<int>.

Above all, the main philosophical difference between Java's default methods and C#'s extension methods is that C# lets you inject methods into types you do not control (which is surely convenient for developers), whereas Java's extension methods are a first-class part of the API in which they appear (they are declared in the interface, they are reflectively discoverable, etc.) This reflects several design principles; library developers should be able to maintain control of their APIs, and library use should be transparent -- calling method x() on type Y should mean the same thing everywhere.

Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
  • 1
    Coming to speak of extension methods and Java ... Is there a chance that Java somewhen in Java10+ or so will have them? I mean is there a general problem that prevents Java from having extension methods like binary backwards compatibility? – OlliP Jan 22 '16 at 13:56
  • 7
    Magic 8 ball says: "don't count on it." – Brian Goetz Jan 22 '16 at 15:26
  • 2
    Can you link to a discussion about "considered and rejected", I really want to understand why? Every library and application has its own "CollectionUtils", "IOTools", "IteratorExtensions", etc... it would be nice if their methods were callable through the instance. – TWiStErRob Apr 03 '16 at 08:59
  • 8
    @TWiStErRob Many reasons, One big one is: API designers should be in control of their APIs. Another is transparency; when someone reading code sees x.m(), they should be able to find m() in the documentation for X, not some random monkeypatch in one of a dozen scopes (this is action-at-a-distance). Relatedly, there's context-freedom; X.m() should mean the same thing in any scope that share the same definition of X, but with use-site extension methods, it doesn't. "It would be convenient" doesn't come remotely close to overcoming these significant obstacles. – Brian Goetz Apr 03 '16 at 14:48
  • 3
    That's a good one, but I feel it restricts freedom of library users. I agree "API designers should be in control of their APIs", but to me it doesn't equate that users of those API can't extend them the way they want. I agree C#-style extensions can be abused (e.g. `((X)null).m()` may not throw NPE :), just as `static import`s can be used excessively. I think these features help development if used in a reasonable way. IDE support can hide that "where did that come from?" complexity. – TWiStErRob Apr 03 '16 at 16:06
  • 5
    Personally I would use it to extend built-ins and libraries with frequently used trivial methods. 1. Polyfill while the API catches up: `String.isEmpty()` (10 years late), `Comparator.reversed()` (16 years late). 2. Add methods which won't be added by the designer because it would "pollute" the API: `Collection.groupBy(v->k)`, `InputStream.copyTo(OutputStream)`. Don't get me wrong, I like that Java is KISS, it's amazing [how few classes it is actually built on](https://www.parleys.com/tutorial/java-the-good-bad-ugly-parts), but sometimes I would need a little bit more. – TWiStErRob Apr 03 '16 at 16:06
  • 2
    could you link to a discussion about "considered and rejected"? – Florian Aug 29 '16 at 12:45
  • 1
    I have to admit a certain sympathy with the "action at a distance" argument. It is the reason that Scala implicits are one of the two languages features that make Scala the single hardest language for me to decipher and use correctly (the other being the couple dozen ways the underscore can be used). OTOH, we routinely rely on a common library of extension methods in C# (that my team developed) to make our own code more understandable (simpler). – melston Apr 01 '17 at 22:40
  • 7
    >> "whereas Java follows the principle that library developers should be able to maintain control of their APIs" This line of reasoning is invalid. An extension method no more changes the API than does a static utility method. Extension methods simply make utility methods more accessible, essentially giving the *illusion* of an extended API for the sake of *convenience* from the perspective of the extension user. – Scott Apr 12 '18 at 19:08
  • 1
    @ScottMcKinney You say "simply" like it is all upside and no downside. But there are very real downsides; some of them were described in the comment above. We chose to value transparency in reading code over convenience in writing code. You may wish we'd made a different choice, but this is why Java works this way. – Brian Goetz Apr 12 '18 at 21:24
23

C# extension methods are just syntactic sugar for static methods that take the extended type as first argument. Java default methods are something completely different. To mimic C# extension methods, just write usual static methods. You will not have the syntatic sugar, however; Java does not have this feature.

Java default methods are real virtual methods. For example, they can be overridden. Consider a class X inheriting from an interface I that declares a default foo() method. If X or any of its super classes declares no own foo() method, then X will get the foo() implementation of I. Now, a subclass Y of X can override X.foo() like a usual method. Thus, default methods are not only syntactic sugar. They are real extensions of the method overriding and inheritance mechanism that cannot be mimicked by other language features.

Default methods even require special VM support, so they are not even a compiler only feature: During class loading, the hierarchy of a class has to be checked to determine which default methods it will inherit. Thus, this decision is made at runtime, not at compile time. The cool thing about it is that you do not have to recompile a class when an interface it inherits gets a new default method: The VM will, at class load time, assign that new method to it.

Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
gexicide
  • 38,535
  • 21
  • 92
  • 152
  • Whilst I understand your answer, I don't get why default methods are something "completely different"...what properties mean they aren't just "syntactic sugar" for interfaces? – Cheetah Jun 07 '14 at 14:57
  • 6
    @Cheetah: No, they are far from being syntactic sugar. They are real extensions that even need VM support. See my edit. – gexicide Jun 07 '14 at 17:29
  • 1
    @SoManyGoblins: Feel free to propose an edit then or at least explain what you think is wrong about my answer (and what would be correct instead). Your comment is not actionable. – gexicide Oct 11 '18 at 11:38
  • You're right @gexicide, I deleted my comment, I was probably having a bad day, I apologise. – SoManyGoblins Oct 20 '18 at 05:33
  • 1
    Default methods seem like multiple inheritance in disguise. – Shameer Oct 31 '18 at 15:10
  • @Shameer Java always had multiple inheritance of _types_. What default methods add is multiple inheritance of _behavior_. The problems we typically associate with "multiple inheritance" in languages like C++ come from multiple inheritance of _state_, which Java does not have. – Brian Goetz Nov 09 '18 at 21:29
8

It is possible to have extension methods with some tricks.

You may give a try to Lombok or XTend. Although extension methods don't come with the out of the box Java implementation, both Lombok and XTend offers a fully working solution.

Lombok is a simple standalone code processing framework, which makes most of the criticized Java specific hassle less painful, including extension methods: https://projectlombok.org/features/experimental/ExtensionMethod.html

Xtend http://www.eclipse.org/xtend/ goes a few lightyears forward, and implements a language which is a combination of the best parts of modern languages such as Scala on top of Java and Java type system. This allows implementing some classes in Xtend and others in Java within the same project. The Xtend code complies to valid Java code, so no JVM magic happens under the hood. On the other hand, it is a little too much if you have only extension methods missing.

JPropel https://github.com/nicholas22/jpropel-light implements LINQ style extension methods in Java using Lombok. It may worth of a peek :)

Gee Bee
  • 1,794
  • 15
  • 17
0

In addition to Lombok and Manifold, there is now also fluent, which allows you to call any static method as an extension method. For example:

import static java.util.Collections.sort;

sort(Arrays.asList(3, 2, 1));    // vanilla java
Arrays.asList(3, 2, 1).sort();   // fluent
Roger Keays
  • 3,117
  • 1
  • 31
  • 23