Java Forum / General / December 2007
Protected and package in iterface
Philipp - 17 Dec 2007 18:04 GMT Lew wrote in thread "Interface":
> What maxnesler forgot to show is that the implementing class declares > the method to be 'public', which is implied automatically in the > interface declaration Why did the people writing the Java specs decide that an interface should not contain protected and package methods?
I can imagine several cases where this would be useful.
Phil
Lew - 18 Dec 2007 00:50 GMT > Lew wrote in thread "Interface": > > What maxnesler forgot to show is that the implementing class declares [quoted text clipped - 5 lines] > > I can imagine several cases where this would be useful. Then you want abstract classes - they are like interfaces in that they cannot be instantiated, but unlike in that they can contain implementation.
The whole idea of an interface is that it's pure public contract. Including (package-)private or protected methods or, indeed, any implementation just isn't part of what it's for.
Perhaps you can describe what such a feature in an interface would give you that isn't available from the existing mechanisms?
 Signature Lew
Philipp - 18 Dec 2007 09:36 GMT >> Lew wrote in thread "Interface": >> Why did the people writing the Java specs decide that an interface [quoted text clipped - 4 lines] > Perhaps you can describe what such a feature in an interface would give > you that isn't available from the existing mechanisms? Multiple inheritance inside a package for example. You develop a package, and internally you want your classes to implement some interface. But you don't want those methods to be public, just package visible. You don't want to let the outside world know about the internal functioning of your lib/package (there's a public API for that), but still want to have the power of the interface construct when developping the lib.
Phil
Lew - 18 Dec 2007 15:38 GMT >>> Lew wrote in thread "Interface": >>> Why did the people writing the Java specs decide that an interface [quoted text clipped - 13 lines] > still want to have the power of the interface construct when developping > the lib. So make the interface itself package-private, or nest it and declare it any access level you want. Doesn't that do what you need?
 Signature Lew
tam@milkyway.gsfc.nasa.gov - 18 Dec 2007 20:38 GMT > >>> Lew wrote in thread "Interface": > >>> Why did the people writing the Java specs decide that an interface [quoted text clipped - 19 lines] > -- > Lew While I think that keeps knowledge of the interfaces from the public, the requirement that methods be public makes it hard to hide those.
E.g., in package 'vehicles' we have interfaces Serviceable and Warranteeable with methods service and warrantee that should only be used within the package. The interfaces are declared with package visibility. We create a public class Car (in vechicles) which implements these interfaces. If I now create an instance of Car and use it outside the package, I can't cast it explicitly to Serviceable or Warranteeable, but I can access the service and warrantee methods.
So to use interfaces I need to break encapsulation. When I tested this I found even the interfaces are pretty visible. E.g., if I try
System.out.println("Try to access interface:"+ Class.forName("vehicles.Serviceable").isInstance(car));
to the Tester class below, it runs fine (and prints true). An explicit use of instanceof will fail in compilation.
Regards, Tom McGlynn
Code for above: public class Tester {
public static void main(String[] args) {
Car car = new Car(); car.service(); car.warrantee(); } } ---- package vehicles; public class Car implements Serviceable, Warranteeable {
public void service() { System.out.println("Service called"); } public void warrantee() { System.out.println("warrantee called"); } } ---- package vehicles; interface Serviceable { void service(); } ---- package vehicles; interface Warranteeable { void warrantee(); }
Joshua Cranmer - 18 Dec 2007 22:55 GMT >> So make the interface itself package-private, or nest it and declare it any >> access level you want. Doesn't that do what you need? >
> While I think that keeps knowledge of the interfaces from the public, > the requirement that methods be public makes it hard to hide those. [quoted text clipped - 6 lines] > use it outside the package, I can't cast it explicitly to Serviceable > or Warranteeable, but I can access the service and warrantee methods. While not quite the same thing, this should be sufficient:
public class Car { class PackageView implements Serviceable, Warranteeable { // Methods, etc. }
PackageView getPackageView() { return new PackageView(); } }
It's a cheap-ish hack, but it does a fair job of emulating C++'s protected or private inheritance.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
tam@milkyway.gsfc.nasa.gov - 18 Dec 2007 23:24 GMT > t...@milkyway.gsfc.nasa.gov wrote: > >> So make the interface itself package-private, or nest it and declare it any [quoted text clipped - 29 lines] > Beware of bugs in the above code; I have only proved it correct, not > tried it. -- Donald E. Knuth I'm sure there are ways to get around this but it seems like a lot of work. E.g., wouldn't this mean that I need to define a PackageView class inside each vehicle type (Bicycle, Trolley, Boat...)? It does seem a bit hackish to me... It seems to obfuscate what would be a straightforward inheritance tree.
In practice this hasn't been a real issue for me, but I tend to write code with rather simple class relationships and I probably make too much public anyway.
Regards, Tom McGlynn
Lew - 19 Dec 2007 03:51 GMT Joshua Cranmer <Pidgeo...@verizon.invalid> wrote:
>> While not quite the same thing, this should be sufficient: >> [quoted text clipped - 11 lines] >> It's a cheap-ish hack, but it does a fair job of emulating C++'s >> protected or private inheritance.
> I'm sure there are ways to get around this but it seems like a lot of > work. E.g., wouldn't this mean that I need to define a PackageView > class inside each vehicle type (Bicycle, Trolley, Boat...)? It does > seem a bit hackish to me... It seems to obfuscate what would be a > straightforward inheritance tree. Whatever. It took me about 15 minutes to work up this SSCCE in 3 files:
// testit/InnerFace.java package testit;
/* p-p */ interface InnerFace { public void foo(); }
// testit/Fimpl.java package testit;
/** Fimpl - . */ public class Fimpl implements Runnable { /** Keep the interface on the down-low. */ /* p-p */ static class NestedFimpl implements InnerFace { @Override public void foo() { System.out.println( "NestedFimpl.foo()" ); } }
private volatile InnerFace face;
/** No-arg constructor. */ public Fimpl() { this( null ); }
/* p-p */ Fimpl( InnerFace f ) { face = (f == null? new NestedFimpl() : f); }
/* p-p */ void setFace( InnerFace f ) { face = (f == null? new NestedFimpl() : f); }
/* p-p */ InnerFace getFace() { return face; }
/** Delegate an action to <code>foo()</code>. */ @Override public void run() { face.foo(); }
/** Main method. * @param args <code>String []</code> program arguments. */ public static void main( String[] args ) { Fimpl fimpl = new Fimpl(); fimpl.getFace().foo(); fimpl.run(); fimpl.setFace( new InnerFace() { @Override public void foo() { System.out.println( " AnonyFace.foo()" ); } }); fimpl.run(); } }
// testit/other/TestFimpl.java package testit.other;
import testit.Fimpl;
/** TestFimpl - . */ public class TestFimpl { /** Main method. * @param args <code>String []</code> program arguments. */ public static void main( String [] args) { Fimpl fimpl = new Fimpl(); // InnerFace face = fimpl.getFace(); // not enough access rights fimpl.run(); } }
 Signature Lew
tam@milkyway.gsfc.nasa.gov - 19 Dec 2007 14:20 GMT > > It does > > seem a bit hackish to me... It seems to obfuscate what would be a > > straightforward inheritance tree. > > Whatever. It took me about 15 minutes to work up this SSCCE in 3 files: ...
> Lew Well I'm not sure whether you're trying to support or refute my point. To me the code posted seems to support it, in the sense that it conceals the relationship between the classes and interfaces, i.e., here that a Fimpl has the capabilities of an InnerFace. It does allow that capability to be hidden from the public which is great, but it seems less clean, clear and flexible than what would be possible if interfaces could have non-public methods, which is where this thread started. As always workarounds are possible, but there seems to be a real cost in this restriction on interface methods, and I've not seen a corresponding benefit.
Not that things are going to change. Since the language spec allows (and conventions encourage) coders to drop the public qualifier on interface methods, allowing non-public methods in interfaces would break vast amounts of existing code.
Regards, Tom McGlnn
Lew - 19 Dec 2007 15:55 GMT > Well I'm not sure whether you're trying to support or refute my > point. To me the code posted seems to support it, in the sense that > it conceals the relationship between the classes and interfaces, i.e., Which is what you asked for.
> here that a Fimpl has the capabilities of an InnerFace. It does allow > that capability to be hidden from the public which is great, but it > seems less clean, clear and flexible than what would be possible if "Seems" is such a weasel word. In this case, it means that you are resisting the idiomatic Java way of doing things because you want your own internal ideal language. Java ain't that, so learn to live with Java's way.
> interfaces could have non-public methods, which is where this thread > started. As always workarounds are possible, but there seems to be a > real cost in this restriction on interface methods, and I've not seen > a corresponding benefit. It's not a real cost, it's one you made up.
My point is that there isn't any complexity or difficulty to the idiom. It only took about 15 minutes to work up that example. Come on! How hard is that?
To anyone used to reading Java, the code is hardly complex at all. Just because you think it looks hairy doesn't make Java's way bad. Get used to Java and it'll look a lot better to you.
It's a poor workman who blames his tools.
 Signature Lew
tam@milkyway.gsfc.nasa.gov - 19 Dec 2007 19:51 GMT > t...@milkyway.gsfc.nasa.gov wrote: > > Well I'm not sure whether you're trying to support or refute my > > point. To me the code posted seems to support it, in the sense that > > it conceals the relationship between the classes and interfaces, i.e., > > Which is what you asked for. [Seem to have lost the first version of this... Apologies if this comes twice.]
There are a couple of meanings of conceal that are relevant here and perhaps I should have been clearer. It is good that the interfaces and methods are not visible to the public. However it is not good that the relationship between the classes and interfaces is obscured in the code and harder to use for those coding within the package.
E.g., which of these expresses the relationship between classes and interfaces more clearly:
class Car implements Serviceable {...}
or
class Car { class ServiceDelegate implements Serviceable {...} Serviceable delegate = new ServiceDelegate()
I find the first a lot clearer but the second is required to hide interface methods from the public.
Similarly I find it easier and clearer to invoke void someMethod(Sericeable item) {...} as someMethod(car) rather than someMethod(car.delegate) or someMethod(car.getServiceDelegate())
The relationship between Car and Serviceable is explicit in the former approach and only implicit in the later. So it's a lot easier for a reader to miss the relationship there. Java has a standard and simple way to restrict visibility but it cannot be used as flexibly for interfaces as, e.g., in abstract classes. The question in this thread is "Why?".
It's perfectly feasible to things the later way, but I don't think it's as clear. To me that is a real cost.
...
> It's not a real cost, it's one you made up.
> My point is that there isn't any complexity or difficulty to the idiom. It > only took about 15 minutes to work up that example. Come on! How hard is that? [quoted text clipped - 4 lines] > > It's a poor workman who blames his tools. Well I guess it takes a long time since I've been coding in Java for over a decade. More seriously I am not blaming Java. I am trying to understand why a choice was made. So far I've not seen any obvious reason why the choice to restrict interfaces to public methods was made. I'd not be surprised to find that there is some excellent technical reason, e.g., something involving runtime resolution of methods or interface inheritance but so far the discussion suggests the authors of the language may not have thought about how interfaces might be useful in restricted contexts. I'd be delighted if someone pointed out some other reason. It would probably illustrate some aspect of language design with which I'm not familiar.
Regards, Tom McGlynn
> -- > Lew Lew - 19 Dec 2007 16:06 GMT > As always workarounds are possible, but there seems to be a > real cost in this restriction on interface methods, and I've not seen > a corresponding benefit. This was no "workaround". The only difference between what Java does and what you want is that Java makes the whole interface, say, package-private. That does exactly what you want, make the methods of that interface available only to the package, with less code than if one had to mark every method.
It also keeps the self-documenting nature of 'interface' intact - that an interface defines the public face to a type, the part others can see. If that's not what you mean to do, then an interface is the wrong thing to use. Private, package-private and protected methods exist for the purpose of implementation, yes, implementation, not contract, and therefore belong in a class, for you, an abstract class, as was stated waaay upthread.
It would be silly and damaging to specify implementation in an interface. It's against their very raison d'être.
My code points out how very easy it is - easy! - to contain the effects of an interface to package level, using three different common Java idioms - a top-level type declaration, a nested type declaration, and an anonymous inner declaration. All three idioms effortlessly contained their effects to package level in a way that you call a "real cost", "restriction", and that you have "not seen a corresponding benefit".
The cost is zero. The benefit is that interfaces perform their architectural role of specifying a contract, only, and that their effect can be contained to arbitrary levels of protection so transparently that you misd-attribute the complexity of an inner-class declaration to the lack of containment of the interface. The interface was so well contained that its contained nature was invisible to you. It really doesn't get any more effortless than that.
Unlike your approach, where one has to wonder method by method what the containment level is. Java's approach is much simpler, to the point where the effort vanishes altogether.
 Signature Lew
Mark Space - 19 Dec 2007 20:17 GMT > Not that things are going to change. Since the language spec allows > (and conventions encourage) coders to drop the public qualifier on > interface methods, allowing non-public methods in interfaces would > break vast amounts of existing code. I wonder if Sun could re-use the 'package' key-word to mean package private. This would allow new interfaces to explicitly declare a package private methods.
interface SomeInterface { package someMethod(); }
To make things cleaner, I think I'd require public interfaces to have only public methods, and 'package' interfaces to have only 'package' methods. An interface with no 'package' modifier would default to the current behavior.
interface PublicInterface [ someMethod(); // Defaults to public, package not allowed. }
package interface PackageInterface { anotherMethod(); // Defaults to package, public not allowed. }
Lew - 20 Dec 2007 01:17 GMT To make things cleaner, I think I'd require public interfaces to have
> only public methods, and 'package' interfaces to have only 'package' > methods. An interface with no 'package' modifier would default to the > current behavior. > > interface PublicInterface [ The absence of a keyword means package-private access.
> someMethod(); // Defaults to public, package not allowed. > } > > package interface PackageInterface { > anotherMethod(); // Defaults to package, public not allowed. > } This buys nothing. The methods of a package-private interface are visible only within the package anyway, so the current setup already accomplishes this. In fact, the misnamed "PublicInterface" above would be exactly right for such a thing with no new keywords needed.
 Signature Lew
Roedy Green - 18 Dec 2007 01:41 GMT >Why did the people writing the Java specs decide that an interface >should not contain protected and package methods? I think the original idea was interfaces were invented to allow people to write code without having access to any existing implementation, just the "blueprints". They would allow strangers to plug in their code into yours. This necessarily meant public.
After there were invented, I think it came clear they have wider use, but by then it was too late to allow scope modifiers.
see http://mindprod.com/jgloss/interface.html
I describe them as the "duct tape" of Java.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Joshua Cranmer - 18 Dec 2007 03:37 GMT > Why did the people writing the Java specs decide that an interface > should not contain protected and package methods? > > I can imagine several cases where this would be useful. Let me point out that there are two separate uses of interfaces in Java: 1. An interface à la the ones defined by IDL. 2. A replacement for function pointers.
In the first case, anything other than public accessors and constant values are pointless. The interface is describing how the conforming implementation must provide its public API; anything not related to this external API is not provided, giving the implementor free choice to decide how to implement as long as it faithfully fulfills the contracts of the interface API. org.w3c.dom is, IMHO, the best example of when an interface is used in this sense.
The second case merely arises out of two thorns in the Java programming language: the lack of pointers to functions, and the impossibility of multiple inheritance. java.awt.event is the prime example of the use of interfaces as callbacks--the methods are not "I will do XXX if you call me" but "call me if you do XXX". Arguably, the use of protected and package-private methods are feasible here, but keeping strictly to the idea of callback should eliminate much of the need. I would be in favor of a mechanism to not advertise the implementation of an interface, but I do not see how that could be feasible (C++'s public/protected/private inheritance doesn't fit the model here).
Judging from the name of the keyword, I am guessing--I repeat, this is only a guess--that an interface was originally designed for the first flavor and that the second flavor was brought about at a bout of simplification of the language towards the end of the initial process.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|