13

I understand the idea of package scope, and at times have even thought I wanted it. However, every time I set down with a serious intent to try using it I discovered it did not fit the needs I thought it would serve.

My main issue always seems to be that the things that I wish to limit the scope of are never in the same package. They may conceptually all be linked, but the logical division of data within the application has them as separate child packages of a larger package.

For instance I may have a Mission model and I want only other Mission tools, like my missionServices, to use some methods. However, I end up with Missions.models and Missions.services as my packages, so the MissionModel and MissionService are not the same package scope. It never seems like there is a situation where packages appropriately contain the things that I would want to have elevated permissions without also included numerous things I do not wish to have those permissions; and rarely do I feel the advantage of package scoping a method justifies modifying my project architecture to place everything in the same package. Often either Aspects or some sort of inversion of control turn out to be the better approach to whatever problem I briefly considered package scoping for.

I'm curious rather this is generally considered true across all Java developers, or is just a fluke of the work I do. Is package scope utilized much in the real world? Are there many cases where it's considered good form to use, or is it seen mostly as a legacy behavior to rarely be exploited in modern development?

I am not asking anything about why package private scope is default, I'm asking when it should be used regardless of the defaults. Most discussions as to why it is default don't really get into when package scope is actually useful, instead arguing simply for why the other two commonly used scopes should not be default so package wins by process of elimination. In addition, my question is about current state of development. Specifically, have we developed to the point where other tools and paradigms make package scope less useful then it was back when the decision to make it default made sense.

dsollen
  • 1,123
  • 1
  • 12
  • 28
  • Thought experiment: what would Java programs look like if you didn't have packages? It could be that you haven't looked at or worked on any *large* Java programs. – Robert Harvey Aug 26 '15 at 14:58
  • Look at the code for `java.util.String` and `java.util.Integer`. –  Aug 26 '15 at 14:59
  • @RobertHarvey Oh packages are needed, I'm asking specifically about the package scope for methods and variables. Packages as a way of logically dividing code and making it easier to export and load logical units of data are a must! As to the package scope, I don't think I can personally think of any large application software I saw using it, though I admit I don't dig into others source code as much as some. – dsollen Aug 26 '15 at 15:01
  • 3
    possible duplicate of [Why did Java make package access default?](http://programmers.stackexchange.com/questions/220053/why-did-java-make-package-access-default) – gnat Aug 26 '15 at 15:02
  • Oh, is that the question? Why package access is the default? Seems like a natural choice to me. – Robert Harvey Aug 26 '15 at 15:04
  • @RobertHarvey not why it's default. Instead I'm asking when it is useful to use. I find that usually it does not help me with encapsulation and I'm curious when it is the right choice Even the linked question above primary reasoning is that package access is sloppy but it's okay to let sloppy programers be kind-of-sloppy within packages, which doesn't sound a significant argument in favor of package access. Though from looking at String and Int I'm thinking it's biggest advantage is not providing security so much as avoiding cluttering the public API of libraries provided to others? – dsollen Aug 26 '15 at 15:13
  • 2
    The top-voted answer on the duplicate question covers the most important use for package-private, implicitly answering why it is useful. –  Aug 26 '15 at 21:30
  • 2
    I'm not at all convinced by the duplicate. This question is asking "What is package scope for?" while the other is asking (among other things) "Given package scope is the default, what is private scope for?" Plus the accepted answer on the dupe and the accepted answer here are making completely different points. – Ixrec Aug 30 '15 at 16:05

5 Answers5

5

Sometime i escalate the visibility of private or protected methods to package to allow a junit-test to access some implementation detail that should no be accessed from outside.

since the junit-test has the same package as item-under-test it can access these implementation details

example

  public class MyClass {
    public MyClass() {
        this(new MyDependency());
    }

    /* package level to allow junit-tests to insert mock/fake implementations */ 
    MyClass(IDependency someDepenency) {...}
  }

It is debatable if this is a "good" usage or not but it is pragmatic

k3b
  • 7,488
  • 1
  • 18
  • 31
  • 2
    I always put tests in a different package, otherwise I find I left some key method in default scope which doesn't allow anyone else to call it... – soru Aug 26 '15 at 19:33
  • I never do it with methods, but it's a nice feature to use for injected dependencies. For example when testing EJBs, injected EntityManagers can be mocked by setting a package level EM with a Mock object where it'd at runtime be injected by the application server. – jwenting Aug 27 '15 at 10:22
  • Why elevate `protected` to package-scope? `protected` _already_ supplies package access. It's a bit of a weird quirk, but I think they didn't want to require compound scope declarations such as `protected packagescope void doSomething()` (which also requires a new keyword). – tgm1024--Monica was mistreated Nov 27 '17 at 05:15
2

Throughout the java.util.* package there are instances where code is written with package level protection. For example, this bit of java.util.String - a constructor in Java 6:

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

or this getChars method:

/** Copy characters from this string into dst starting at dstBegin. 
    This method doesn't perform any range checking. */
void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, offset, dst, dstBegin, count);
}

The reason for this is that the designers of the code (and java.util.* can be thought of as a rather large library) wanted the ability to have faster performance at the cost of a loss of various safety (range checks on arrays, direct access to other fields that imply the implementation rather than the interface, 'unsafe' access to parts of the class that are otherwise considered to be immutable via public methods).

By restricting these methods and fields to only be accessed by other classes in the java.util package, it makes for closer coupling between them but also avoids exposing these implementation details to the world.

If you are working on an application and don't have need to worry about other users, package level protection isn't something you need to worry about. Other than various aspects of design purity, you could make everything public and be ok with that.

However, if you are working on a library that is to be used by others (or want to avoid entangling your classes too much for later refactoring), you should use the strictest level of protection afforded to you for your needs. Often this means private. Sometimes, however, you need to expose a little bit of the implementation details to other classes in the same package to avoid repeating yourself or to make the actual implementation a bit easier at the expense of the coupling of the two classes and their implementations. Thus, the package level protection.

  • 1
    I did look through java.util and I do see that. However, i also notice it's a LARGE library. Now of days it seems libraries that large are rarely written without using sub-packages; and it's those sub-package divisions that lead to limits. I'm not saying java.util is wrong, but it seems like they could get away with a large package only because they had *EXTREMELY* good programers they could trust to do everything right with rather limited encapsulation within a package; I would feel naked trusting that much potential to do bad to average developers that may work on similar packages as me. – dsollen Aug 26 '15 at 15:21
  • 1
    @dsollen If you dig into Spring, and Hibernate or similar large libraries you will find similar things. There are times where you need the closer coupling. One *should* have the opportunity to code review the submissions and make sure everything is correct. If you don't need the closer coupling, or don't trust the other coders at all, then public fields, or package or protected fields or methods isn't always appropriate. However, that doesn't mean that it isn't useful. –  Aug 26 '15 at 15:26
  • in short, I would be tempted to make more restricted packages and not worry about the level of optimization (which is just a waste in 95% of projects) for my everday needs. Thus my follow up question becomes is package level scope a very specific optimization potential used only in certain extensively used massive APIs? IE only the greats will need, or want, to relax protections to that degree? Are there reasons that good programmers working on even 'standard' API with smaller user bases would find use for this? – dsollen Aug 26 '15 at 15:26
  • Didn't get my follow up post in fast enough :) I understand and see the point you made, I'm not debating it at all. More just posing a follow up question as to it's usefulness to the rest of us good programmers, but ones that don't get to work on such huge APIs. Specifically, is it mostly an optimization at expense of encapsulation tradeoff that is only made when you really *really* need to tweak performance. – dsollen Aug 26 '15 at 15:28
  • 2
    @dsollen it isn't about performance (though that is one reason to expose implementation) but rather encapsulation. You do it to avoid repeating the code for `Integer.toString()` and `String.valueOf(int)` can share code without exposing it to the world. The `java.util` classes are to work in concert to provide a larger whole of functionality rather than being individual classes that are entirely islands unto themselves - they are together in a package and share implementation functionality via package level scoping. –  Aug 26 '15 at 15:42
2

It's not all that useful, especially as a default, in a world where people tend to use the dotted names of packages as if they were sub-packages. Because Java has no such thing as a sub-package, so x.y.internals has no more access to x.y than it does to a.b. Package names are either the same or different, a partial match is no different from having nothing in common.

I guess the original developers never expected that convention to be used, and wanted to keep things simple without adding the complexity of Ada-style hierarchical packages.

Java 9 is sort of addressing this, in that you can put several packages in a module and only export some. But that will make the package scope even more redundant.

In an ideal world, they would change the default scope to 'module scope, if a containing module exists, otherwise package scope'. Then you can use it for sharing implementation within a module, allowing refactoring without breaking exported interfaces. But maybe there is some subtlety why that would break backwards compatibility, or be otherwise bad.

soru
  • 3,625
  • 23
  • 15
  • I find the java 9 comment interesting. I think a simple ability to recognize package herachies and somehow define package scope relative to some parent package (using annotations?) would be nice. – dsollen Aug 27 '15 at 14:02
  • 1
    @dsollen, perhaps, but my first inclination is that we'd be starting to gold-plate the tire irons with that one. A far better first step to clarity (which brings safety along to some extent) in my opinion would be to invent a actual package scope keyword. It might even be "package" :) – tgm1024--Monica was mistreated Nov 27 '17 at 05:20
2

The type of cohesion your describing is not really the best example of where you would use package access. Package is handy for creating components, modules that are interchangable on an interface.

Here is a rough example of a scenario. Suppose your code was reorganized to be more around functional cohesion and componentization. Perhaps 3 jars like:

**MissionManager.jar** - an application which uses the Java Service Provider Interface to load some implementation of missions, possible provided by a 3rd party vendor.

**missions-api.jar** - All interfaces, for services and model
    com...missions
        MissionBuilder.java   - has a createMission method
        Mission.java - interface for a mission domain object
    com...missions.strategy
        ... interfaces that attach strategies to missions ...
    com...missions.reports
        .... interfaces todo with mission reports ....

   **MCo-missionizer-5000.jar** -  provides MCo's Missionizer 5000 brand mission implementation.
       com...missions.mco
                  Mission5000.java - implements the Mission interface.
       com...missions.strategy.mco
              ... strategy stuff etc ...

By using package level in the Mission5000.java, you can unsure that no other package, or component such as the MissionManager can tight couple to mission implemetation. That is only the "3rd party" provided component from "M co" actually creates there own special branded implementation of a Mission. The Mission Manager must call the MissionBuiler.createMission(...) and use the defined interface.

This way if the Mission implementation component is replaced we know that the implementers of MissionManager.jar didn't bypass the api and use MCo's implementation directly.

Hence we can swap out MCo-missionizer5000.jar with a competing product. (Or perhaps a Mock for unit testing the Mission Manager)

Conversely MCo can do some amount of hidding their proprietary missionizer trade secrets.

(This is related enforcing Instability and Abstractness ideas in components as well.)

Chris
  • 83
  • 3
-1

Because package scope in java is not designed in the hierarchical way it is hardly useful. We do not use package scope at all and define all classes as public.

Instead we use our own access rules based on the package hierarchy and predefined package names.

If you are interested in details google for "CODERU-Rules".