Why friend directive is missing in Java?
Asked Answered
N

8

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.

Nautch answered 10/1, 2011 at 14:5 Comment(0)
S
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).
Sidra answered 10/1, 2011 at 14:12 Comment(6)
–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 (That said, I am wholly satisfied with package visibility, but claiming that friend breaks encapsulation is still wrong.)Deyo
@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.Reluctant
@Reluctant - 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.Cheongsam
@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.Reluctant
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.Sidra
Breaks encapsulation from class perspective but NOT from namespace perspective. Sometimes you want to encapsulate things into a namespace and not just a class.Related
C
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.

Chivaree answered 10/1, 2011 at 14:9 Comment(3)
the extremely huge number of lines of java in production at this moment can attest that any random design choice in java is devine.Ritchie
@Ritchie Nice comeback. However i was half joking :)Chivaree
friend exists in the form of package visibility. It's just not as flexible in Java.Reluctant
S
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).
Sidra answered 10/1, 2011 at 14:12 Comment(6)
–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 (That said, I am wholly satisfied with package visibility, but claiming that friend breaks encapsulation is still wrong.)Deyo
@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.Reluctant
@Reluctant - 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.Cheongsam
@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.Reluctant
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.Sidra
Breaks encapsulation from class perspective but NOT from namespace perspective. Sometimes you want to encapsulate things into a namespace and not just a class.Related
P
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.

Pinkney answered 27/5, 2013 at 6:54 Comment(2)
I wish I could upvote this answer 100x. This "friend is bad" ideology is a dangerous one.Reluctant
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.Cheongsam
V
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.

Verdin answered 10/1, 2011 at 14:36 Comment(2)
Inner but no partial.Related
@Vozzie, true, but what has this to do with friend?Verdin
L
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.

Lixivium answered 23/7, 2013 at 14:24 Comment(0)
H
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.

Holmic answered 10/1, 2011 at 14:19 Comment(12)
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.Goddaughter
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.Holmic
@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.Toshiatoshiko
@Toshiatoshiko 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.Reluctant
@Reluctant 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.Toshiatoshiko
@Toshiatoshiko That's true if serialization is encapsulated inside the class as well...you still are going to have to make changes to serialization...Reluctant
@Reluctant You should consider whether the private stuff should be serialised at all.Toshiatoshiko
@Toshiatoshiko Is that a real question? If it didn't need to be serialized, it would be marked transient...Reluctant
@Reluctant 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.Toshiatoshiko
@Toshiatoshiko 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.Reluctant
@Reluctant 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.Toshiatoshiko
@Toshiatoshiko 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.Reluctant
K
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...

Krystinakrystle answered 10/1, 2011 at 14:21 Comment(0)
O
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.

Ol answered 10/1, 2011 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.