The Source for Java Technology Collaboration
User: Password:



Meeraj Kunnumpurath

Meeraj Kunnumpurath's Blog

Does Java need friends?

Posted by meeraj on August 21, 2005 at 04:20 AM | Comments (12)

One of the stumbling blocks I have run into, in my few years of using Java is Java's lack of flexible access visibility mechanisms. The access mechanisms are strictly constrained within the semantics of private, package, protected and public access modifiers. However, in ceratin scenarios this can be a bit constraining.

A good example if often when you use light-weight domain modelling using Java. You woudln't want to expose the internal state of your domain objects to external entities. However, you are forced to add the so called public getters and setters to your private instance variables so that your persistence frameworks can set them or the view framework can get them. This is indeed an anti-pattern, that breaks one of the cornerstones of object orientation, i.e data encapsulation. These getters and setters are not part of the public behaviour of the entity you are modelling.

There are two solutions that some into my mind,

    A C++ style friend access mechansim, where you can specify arbitrary visibility enablement between classes. This means you can allow the internal state of your domain classes be accessed by only persistent and domain classes.
    Allow the semantics of package and protected access to be extended to hierarchical packages. This means for example, classes in com.acme.domain.persist and com.acme.domain.view would have the same access permissions on the classes within com.acme.domain as the classes within the same package.

Note: Some persistence frameworks do enable private field level access. However, as soon as you deny ReflectPermission in a J2EE environment (recommended by the spec) you will start running into problems.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • I sometimes wish Java had friends too, but can always design around the lack of them.

    Mostly I'm glad Java doesn't have friends.I've seen too much abuse of it in C++.

    I like your second solution, though - introducing a nested hierarchy scope.

    Another possibility is to have something like the Category system in Objective-C. Arbitrary creation of Categories can be controlled by a SecurityManager (eg Category and original class could be constrained to coming from the same sealed jar, etc).

    Posted by: goron on August 21, 2005 at 05:26 AM

  • First, I believe Java 6 or 7 will have such "modules" which allow you to define groups of packages which have access to each other. Second, I think friends are using a hammer to find a needle in a haystack. I mean that I think it's overkill to explicitly define which classes can access each other. Third, I've never wanted Java to have friends, but I have had to do some messy hacks. Currently if I need some class to use some method from a package which is supposed to be package-private, I create a class in that package called InternalTools, and I add utility methods to access the package-private things. I mark it @Deprecated so anyone who uses the class will see it crossed out in their IDE and warnings when compiling. I think this is an okay solution until Java modules.

    Posted by: keithkml on August 21, 2005 at 10:39 AM

  • Sigh, another person wanting to turn Java into C++

    Posted by: jwenting on August 21, 2005 at 11:15 PM

  • A few random thought... If you are really saying that private, protected, package and public visibility modifiers are not enough, then for argument sake lets just say I agree with you. Now instead of stopping at friends, lets just take this argument to it's logical conclusion. Why don't we do away with visbility modifier altogether! I say this because little by little, changes like introduce new ways in which we can encourage developers to violate encapsulation, increase the level of couplings between packages and classes, create more brittle code that is more difficult to maintain. Hey I like this because it sounds like a recipe for job security. Sarcasum aside, we already have Generics which even it's authors are at a loss to be able to explain in full (blogged on java.net). We have autoboxing which doesn't have a clue on how to handle 0 and now we want to add YAC++ feature before we understanding the overall effects that it will have? I never used friends in C++ and I sure as h*ll don't want to deal with them in Java. One last note, persistance frameworks shouldn't need explicit get/set methods as there are other ways to violate encapsulation (which all interfaces to external systems must do). The printOn: method in Smalltalk solved that problem a few decades ago. Kirk Pepperdine http://www.javaperformancetuning.com

    Posted by: kcpeppe on August 22, 2005 at 12:59 AM

  • I really don't think that Meeraj is arguing to relax encapsulation.

    Having had a bit of a discussion about this with him, I think that he is arguing for more richness in the language of encapsulation. It is very frustrating to only have a choice between large packages encapsulated using package friendly, inheritance using protected or making more of a package public than you would like.

    Posted by: bob_boothby on August 22, 2005 at 01:17 AM

  • I do hope Meeraj at least understand that the effect of making this arguement isl a relaxation of the rules of encapsulation or this blog is a poster child for my assertion that we need to understand what we are doing to the language before we start chaning it.

    Java is a product being used in product by more then 4,000,000 developers. Like any other product being used in a production environment (and I mean the environment of developing applications), one has to be fully aware of the ramifications of change before deciding if the change should be made. What is at risk here is the destabilization of development teams ability to produce quality fault free systems for their sponsers (business) in a predictable consistant fashion.

    The C++ experiment was interesting but unfortunately it escaped. The unprecidented mass adoption of Java is evidence that people don't want to go down the road of developing systems in C++ again. Yet we (as a development community) persist in trying to take the simplist beauty and expressivness of Java and corrupt it with structures from C++ that are dubious at best and distructive at worse.

    The notion of friends goes against what I believe (and I don't believe that I'm alone in this belief) good design and coding practices. If there is any metrics to demonstrate this then they must be Demeter and measures of efferent and afferent couplings. IMHO, we shouldn't be considering the inclusion of language features that encourage violations of these standard measures of good design and coding practices.

    Posted by: kcpeppe on August 22, 2005 at 05:06 AM

  • There are two additional motivations in favor of friend access:

    Obfuscation. The lack of 'friend' very often forces apps to expose as public, methods that could otherwise go private. But bytecode obfuscators&optimizators rely on visibility restrictions to do their job -- any methods that can be proven to not be accessed from outside some class/jar are much easier to mark as "safe" for renaming, inlining and other transformations. You can often achieve the same amount of obfuscation efficiency by configuring the obfuscator properly, but I'd rather not have this work and get a very good level of obfuscation by default. And this is a very important issue in closed-source development in Java, because bytecode is so easy to reverse engineer.

    Backwards compatibility. People writing APIs, either Sun/JCP (java.*) or opensource/commercial libraries, have a problem that they often expose internal implementation classes as public. Look for example inside J2SE's rt.jar, there is a boatload of internal classes in packages com.sun.*, sun.* and sunw.*, hundreds of public classes and thousands of public methods. If some application uses these internal APIs, they may break in future J2SE releases when the internal stuff changes. In the J2SE platform, security managers are often used to restrict access to internal classes at runtime; but this solution has a performance cost, and it's a very cumbersome solution for general use -- most opensource or commercial libraries don't do anything to restrict access to internal classes. Then you want to change these classes in a major new release, and your job is harder because some stupid (but important) client have used internal APIs. And I'm not creating theorethical scenarios here. Look for example at the Eclipse project; it's very frequent to have third-party (non-Eclipse.Org) plug-ins fail in new releases of the SDK/JDT, because they were relying internal APIs. For example, I saw this happening with JBossIDE (I had to patch 1.5M1 manually to run on 3.1, before they released 1.5M2). And this happens even though Eclipse makes an awesome effort in separating public APIs from internal ones, through its advanced plug-in runtime and config files. But some plugin writers are brain-damaged, and others want to gain some competitive advantage by exploring internal APIs that have yet to be exposed as proper extension points. (Version 3.1 provides PDE tools to flag and warn about dependencies on internal APIs, but it's not a full solution, you can still invoke those APIs if you really want.)

    Posted by: opinali on August 22, 2005 at 05:47 AM

  • opinall, "The lack of 'friend' very often forces apps to expose as public, methods that could otherwise go private." Deligation is your friend... And we won't to put a bigger more powerful weapon into the hands of the "brain-damaged"? Sometimes we re-cycle garbage and sometimes the best thing to do is take it out back and burn it ;)

    Posted by: kcpeppe on August 22, 2005 at 11:30 PM

  • imho, keithkml hits the nail on the head - JSR277 solution to this sounds like a much better direction

    Posted by: asjf on August 23, 2005 at 05:55 AM

  • JSR277 modules == .NET assemblies. Assembly visibility in C# is exactly how Java should do it. And NO, please NO friends in Java, this is /was a very silly concept.

    Posted by: sentinel101 on August 23, 2005 at 07:02 AM

  • I just have to comment on the note about persistence frameworks and enablilng private field level access. I frankly don't see why this is such a problem. I have been using Hibernate for a while and have never experienced - or heard anyone else complain - about this. So, Hibernate really gives you immutable classes if you add a private default constructor as well as private setters.

    Posted by: krismoum on August 23, 2005 at 10:02 PM

  • I don't beleive friend is the way to go. Just like virtual it requires that the developer can predict all potential uses of the class. I'm currently translating a Smalltalk system where of course everything is public. Some times you come across methods that clearly should have restricted visibility, but then there are one or two odd exceptions to the rule. With no time to refactor, you have to leave it public. I think most would agree that to make a system work and perform you have to breach clean interfaces and encapsulation from time to time. keithkml's InternalTools workaround would of course work, at least making other developers aware that it's use is discouraged. It should be accompanied by an above-average-detailed javadoc explaining why it is discouraged, and what you have to bevare of if you decide to use it, other alternatives etc. . The only other thing i could wish for is a standard annotations for such cases. It could be called @Discouraged, the method would remain public and the InternalTools would not be required. Ideally javac should produce a warning, but code checkers,IDEs or custom tools could also do the trick. I realize that the concept is a paradox, but hey it's not the only one in life ;-)

    Posted by: skamar on August 24, 2005 at 12:19 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds