17

I was wondering why Java has been designed without the frienddirective that is available in C++ to allow finer control over which methods and instance variables are available from outside the package in which a class has been defined.

I don't see any practical reason nor any specific drawback, it seems just a design issue but something that wouldn't create any problem if added to the language.

skaffman
  • 381,978
  • 94
  • 789
  • 754
Jack
  • 125,196
  • 27
  • 216
  • 324

8 Answers8

10

In general i think it was because of the added cognitive complexity and low number of cases in which it creates an improvement.

I would say that the extremely huge number of lines of java in production at this moment can attest that the friend keyword is not really a big loss :).

Please see @dwb's answer for some more specific reasons.

Mihai Toader
  • 11,551
  • 1
  • 27
  • 33
10

Here are a few reasons off the top of my head:

  • friend is not required. It is convenient, but not required
  • friend supports bad design. If one class requires friend access to another, you're doing it wrong. (see above, convenient, not required).
  • friend breaks encapsulation. Basically, all my privates are belong to me, and that guy over there (my friend).
DwB
  • 33,855
  • 10
  • 50
  • 78
  • 21
    –1 for encapsulation. This is a common misunderstanding. It’s simply wrong. While it’s true that `friend` *can* be used to break encapsulation, so can other features be misused. Used correctly, `friend` *enhances* encapsulation because it enables a more fine-grained access control: `friend` replaces use of `public`, not use of `private`. [Technical explanation at the C++ FAQ](http://www.parashift.com/c++-faq-lite/friends.html#faq-14.2) (That said, I am wholly satisfied with package visibility, but claiming that `friend` breaks encapsulation is still wrong.) – Konrad Rudolph Jan 10 '11 at 16:19
  • 2
    @KonradRudolph Absolutely agree. Friend classes are essential for separation of concerns. For example, I have a `Serializer` class that should be allowed to write to the fields of an instance, so I give it friend access. Other classes, cannot specifically write to the fields and must go through the interface which I provide. The only way you can do this in Java is to put everything into the same package. – crush Aug 23 '14 at 16:15
  • @crush - I can think of a dozen ways to address that without friends, but why not just have your class that needs to be serialized implement a serializer interface. Easy, no need for friends, and it can even implement it all using your generic Serializer class. – Joe Zitzelberger Mar 21 '16 at 17:16
  • @JoeZitzelberger Add serialization logic to a POJO object? No, that's not a good solution. I'm guessing the other method you are talking about would be using reflection because that is the ONLY other way to do what I'm talking about without decorating your POJO objects with serialization code. Reflection is not always efficient enough in every scenario, but would suffice in most. – crush Mar 22 '16 at 21:26
  • The concept of POJO is ridiculously silly. An object should hide its data and expose operations for consumption. Serialization is a legitimate operation. A well designed (better than Java) object system would expect a user to provide a serialization target to an object's serialization method and let the object work on the object's data. The classic POJO is just a c Structure that wraps access in getters and setters. Another description is a Pojo is an object that totally exposes its implementation details seemingly in an attempt to maximize coupling. – DwB Mar 22 '16 at 23:10
  • 1
    Breaks encapsulation from class perspective but NOT from namespace perspective. Sometimes you want to encapsulate things into a namespace and not just a class. – Vozzie May 23 '16 at 22:16
7

Only a very naive and inexperienced programmer would advocate against friends. Of course it can be misused, but so can public data, yet that capability is provided.

Contrary to popular opinion, here are many cases, in particular for infrastructure capabilities, where friend access leads to BETTER design, not worse design. Encapsulation is often violated when a method is FORCED to be made public when it really shouldn't be, but we are left with no choice because Java does not support friends.

spaceghost
  • 119
  • 1
  • 4
  • 1
    I wish I could upvote this answer 100x. This "friend is bad" ideology is a dangerous one. – crush Aug 23 '14 at 16:19
  • I would suggest that only a naive and inexperienced programmer thinks they need to let their friends play with all their privates. It breaks encapsulation and causes no end of havoc, when other, simpler approaches are available. – Joe Zitzelberger Mar 21 '16 at 17:12
4

In addition to the aforementioned package visibility, Java also offers inner and anonymous classes which are not only friends by default, but also automatically have a reference to the containing class. Since creating such helper classes is probably the only reasonable way to use friend in C++, Java doesn't need it since it has another mechanism for that. Iterators are a very good example of this.

Sergei Tachenov
  • 22,431
  • 8
  • 51
  • 68
3

Completely agree with spaceghost's statement in his answer

Contrary to popular opinion, here are many cases, in particular for infrastructure capabilities, where friend access leads to BETTER design, not worse design.

My example is simple - if a class A has to provide a special "friend" interface to class B in java we have to place them into the same package. No exceptions. In that case if A is a friend of B and B is a friend of C, A has to be a friend of C which isn't always true. This "friendship transitivity" breaks encapsulation more then any problems which C++ friendship could lead to.

Community
  • 1
  • 1
2

Why not simply think that Java requires friend classes to be co-located ? The package-private visibility allows everyone from the same package to access those members. So you're not only limited to explicitly declared friends, but you allow any (existing or future) friend to alter some members that are specifically designed for this purpose (but not your private stuff). You're still able to fully rely on encapsulation.

Costi Ciudatu
  • 33,403
  • 5
  • 52
  • 89
  • 2
    The problem here is that any class can claim to be a member of any package. This would be the equivalent of me telling a security guard that I'm your friend and the security guard letting me search your room. – Powerlord Jan 10 '11 at 14:36
  • That's not entirely true (you cannot declare a class as belonging to a java.* package, for instance) and besides, if someone really needs this kind of hack (putting a class into the org.apache.commons.logging just to see package-private members), they could very well use reflection and setVisible(true). But I'm not talking about hacks. The Java standard API makes intensive use of package-private members. – Costi Ciudatu Jan 10 '11 at 14:41
  • 2
    @R. Bemrose: The private/protected/public/package visibility mechanism is not intended to be a security feature. It's a programming feature designed to aid encapsulation. – JeremyP Jan 10 '11 at 15:57
  • 1
    @JeremyP `friend` allows you to have one-way relationships, which can come in really handy in situations where you want to allow a class access to your private members, without gaining access to their own. For example, consider a `Serializer` class that needs to write private members of a class. Sure, you could implement some interface, and write the serialization logic on the actual object, but if you wanted to separate concerns fully, then giving a `Serializer` class access to the objects internal members would be even better. You can't have a one-way relationship in Java. – crush Aug 23 '14 at 16:27
  • @crush If you serialise private data, you break encapsulation. You can't change the implementation of the class (possibly adding and removing private members) without breaking the serialiser and any serialisations already produced. – JeremyP Aug 23 '14 at 23:50
  • 1
    @JeremyP That's true if serialization is encapsulated inside the class as well...you still are going to have to make changes to serialization... – crush Aug 24 '14 at 00:50
  • @crush You should consider whether the private stuff should be serialised at all. – JeremyP Aug 26 '14 at 09:40
  • @JeremyP Is that a real question? If it didn't need to be serialized, it would be marked transient... – crush Aug 26 '14 at 13:01
  • @crush Yes, it's a real question. The private stuff should be private to the implementation. An external file is as much an external interface as the UI is, so an external file shouldn't see the private stuff. If it can, you are opening yourself up to undocumented incompatibilities between versions. – JeremyP Aug 26 '14 at 13:49
  • @JeremyP We are talking about serializing an object's state into a byte stream here JeremyP. You would absolutely serialize all the private fields if they were not marked transient. It doesn't matter if the serialization is encapsulated within the same class, or in a separate Serializer class; if the fields of a class change, you will have to change the serialization mappings wherever they are mapped unless you are using reflection or some type of compile time code generation. You are advocating that SRP is less important than encapsulation. I completely disagree. Composition over inheritance. – crush Aug 26 '14 at 15:32
  • 1
    @crush The idea of serialising the internal (private) state of a class is fundamentally broken. If I create a Stack class (for example), it should not matter if I use an array or a linked list internally to store the elements. As soon as I allow you to serialise the private members of my Stack class, I can no longer change the implementation without breaking backward compatibility. – JeremyP Aug 26 '14 at 16:25
  • @JeremyP Only if your serialization mechanism is so naive as to not support backward compatibility. Again. This has **nothing** to do with encapsulation or access to private/protected fields. The same exact statement would be true with public getters/setters Take a `String` field that you change to an `int`. You have to change your setter/getter. Now your serialization is broken. Only naive serialization doesn't account for versioning changes. You keep a map of each iteration, and you have instructions for translating between types. – crush Aug 26 '14 at 16:31
2

Just to add to the other answers:

There is the default package visibility in Java. So, you could call all classes in the same package neighbors. In that case you have explicit control of what you show to the neighbors - just members with package visibility.

So, it's not really a friend but can be similar. And yes, this too leads to bad design...

Goran Jovic
  • 9,040
  • 3
  • 40
  • 74
2

In my opinion some kind of friend feature (not necessarily very similar to C++'s) would be very helpful in some situations in Java. Currently we have package private/default access hacks to allow collaboration between tightly coupled classes in the same package (String and StringBuffer for instance), but this opens the private implementation interface up to the whole package. Between packages we have evil reflection hacks which causes a whole host of problems.

There is a bit of an additional complication in does this in Java. C++ ignores access restrictions whilst resolving function overloads (and similar) - if a program compiles #define private public shouldn't do anything. Java (mostly) discards non-accessible members. If friendship needs to be taken into account then the resolution is more complicated and less obvious.

Tom Hawtin - tackline
  • 139,906
  • 30
  • 206
  • 293