Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #3020

Re: Why only public methods on interfaces?

From Tom Anderson <twic@urchin.earth.li>
Newsgroups comp.lang.java.programmer
Subject Re: Why only public methods on interfaces?
Date 2011-04-10 16:02 +0100
Organization Stack Usenet News Service
Message-ID <alpine.DEB.2.00.1104101453190.14871@urchin.earth.li> (permalink)
References (4 earlier) <KPCdnfEJDvZ0KAPQnZ2dnUVZ_sqdnZ2d@posted.palinacquisition> <XoGdnZ2ah5Y6iQLQnZ2dnUVZ_jednZ2d@earthlink.com> <TcKdnZsfUbuKhALQnZ2dnUVZ_iydnZ2d@posted.palinacquisition> <58-dnYYCMK1urQLQnZ2dnUVZ_gGdnZ2d@earthlink.com> <inrf5h$7ne$1@dont-email.me>

Show all headers | View raw


On Sat, 9 Apr 2011, Mike Schilling wrote:

> "Patricia Shanahan" <pats@acm.org> wrote in message 
> news:58-dnYYCMK1urQLQnZ2dnUVZ_gGdnZ2d@earthlink.com...
>
>> The really unfortunate decision is not the public methods only, but the 
>> decision to make non-specification of access mean public interface 
>> method declarations but package access in class method declarations. 
>> That cuts off any possibility of changing interfaces now to make them 
>> more flexible.
>
> Actually, you could make an argument that "protected" on an interface 
> method would mean "only visible within the package", because it can't 
> mean "and also visible to derived types".

It could mean 'visible to types derived from implementors of the 
interface'. It would mostly act to constrain the access modifier on the 
implementing method.

If you interpreted interface-protected your way, you would have to permit 
implementors to declare their implementations package-access, otherwise it 
would be pointless, and that would mean that you would be writing 
implementations that appeared to have a narrower access modifier than 
their specification.

In code:

package x;

public interface I {
 	protected void m();
}

public class A implements I {
 	protected void m() {} // legal, looks normal, but widens access!
}

public class B implements I {
 	/*package*/ void m() {} // is this legal?
}

package y;

class C extends x.A {
 	void foo() {
 		m(); // i probably shouldn't be able to do this
 		I i = this;
 		i.m(); // i won't be able to do this
 	}
}

Which is why ...

On Sat, 9 Apr 2011, Mike Schilling wrote:

> Unless new syntax like "package-private" is introduced.

That seems like a very good idea. Indeed, a future revision of the 
language could do that, and at the same time deprecate the omission of an 
access modifier altogether.

What i'd really like to see is a slightly more complicated but much more 
expressive system of access control. I worked this out with a friend a 
while ago, and i think the model should be:

1. The universe consists of a tree of things: the leaves are features 
(fields and methods), and the branches are containers (packages and 
classes - classes are also features in some ways, and i don't think that 
causes any difficulty), with the root being the default package. Packages 
can contain packages and classes; classes can contain classes and 
features.

2. Every feature explicitly exposes itself at one scope; it is visible to 
any code defined within that scope, including nested scopes. 'public' 
means it is exposed to the default package. 'private' means that it is 
exposed to the outermost enclosing class. This is as now. A new modifier 
'package' means that it is exposed to the innermost enclosing package. 
This differs from the current default in that it is visible to subpackages 
(the current default is not visible in subpackages, although it is visible 
in nested classes in the same package). The lack of an explicit modifier 
would elicit a compiler warning, and be treated the same as 'package' 
(this widens access to these features, but in a backwards-compatible way).

3. In addition to these simple modifiers, it is possible to explicitly 
specify an exposure scope - this can be any scope enclosing the feature. 
The syntax i would use would be 'private(name.of.scope)'. 'public' is thus 
shorthand for 'private()', 'package' is shorthand for 
'private(innermost.enclosing.package)', and 'private' is shorthand for 
'private(outermost.enclosing.class)'. The scope name is resolved in the 
usual way, so scopes which are classes would not need to be fully 
qualified.

4. In addition to the exposure scope, a feature can be made visible to 
subclasses of its defining class, whatever package they may be in. This is 
done by replacing 'private' with 'protected'; this accepts an explicit 
scope in the same way as 'private'. The natural exposure scope for an 
unqualified 'protected' would be the same as for an unqualified 'private', 
ie the outermost enclosing class, but this would break backwards 
compatibility, so sadly, it must mean 
'protected(innermost.enclosing.package)'. Perhaps we should allow a 
shorthand for the outermost enclosing class, perhaps 'this', so you could 
write 'protected(this)' to allow access only to subclasses and inner 
classes.

The main thing that this gives you is a way to make features visible 
across packages in a hierarchy. This is a frequent problem in large 
projects which are intended to be modules in a larger world (eg on a vast 
project, or libraries for public consumption); a class in org.foo.io might 
need to be visible to one in org.foo or org.foo.core, but should not be 
visible to unrelated code in com.bar. Similarly, methods in a class in 
org.foo often need to be accessible to classes in org.foo.io, but not 
com.bar. At present, you end up with public methods marked 'PRIVATE API, 
DO NOT USE', which is total rubbish. The proposed access system would let 
you scope all these methods to org.foo, and have them visible to 
everything in the project.

What it no longer lets you do is have things in org.foo that are *not* 
visible throughout the project. However, i would suggest that such things 
really belong in a subpackage. The parent package should be minimal, and 
only contain things for general consumption.

It also lets you have features which are visible to subclasses but not the 
rest of the package, which is something i have always wanted.

If we extend the explicit scope notation to accept multiple exposure 
scopes, then we have essentially copied the C++ friend mechanism. That 
would let me solve the classic JPA problem of how i stop unrelated classes 
calling the internal-use-only innerWhatever methods in this scenario (this 
is actually a slight variation in the classic pattern, but i hope it's 
clear):

@Entity
public class Department {
 	@OneToMany(mappedBy="dept")
 	private List<Employee> employees;

 	public void addEmployee(Employee emp) {
 		emp.setDepartment(this);
 	}

 	public void removeEmployee(Employee emp) {
 		emp.setDepartment(null);
 	}

 	void innerAddEmployee(Employee emp) {
 		employees.add(emp);
 	}

 	void innerRemoveEmployee(Employee emp) {
 		employees.remove(emp);
 	}
}

@Entity
public class Employee {
 	@ManyToOne
 	private Department dept;

 	public void setDepartment(Department dept) {
 		if (this.dept != null) this.dept.innerRemoveEmployee(this);
 		if (dept != null) dept.innerAddEmployee(this);
 		this.dept = dept;
 	}
}

At the moment, the methods have to be at least package-access, because 
Employee needs to be able to call them. But with the proposed mechanism, i 
could declare them:

 	private(Employee) void innerAddEmployee(Employee emp)
 	private(Employee) void innerRemoveEmployee(Employee emp)

And access would be restricted to just where they were needed.

Compared to C++'s friendship system (which i don't understand well, so 
correct me if i'm wrong), we have finer-grained control over what is 
exposed (individual features, rather than all the features in the class), 
but coarser-grained control over who we expose it to (classes, rather than 
individual methods). The former is clearly better, because it means we can 
expose the things we need to, whilst keeping most details of the class 
encapsulated. I would argue that the latter is also better, because the 
exposing class has no business knowing which particular methods of the 
friend class are going to make use of the exposure; in the above example, 
i want to be free to refactor the calls from Employee to Department.inner* 
into a separate method (perhaps updateDepartmentEmployeeLists), without 
having to modify Department (particularly because it might be a private 
method - in which case in C++, Department would have to know about a 
private method of Employee!).

tom

-- 
A military-industrial illusion of democracy

Back to comp.lang.java.programmer | Previous | NextPrevious in thread | Next in thread | Find similar


Thread

Why only public methods on interfaces? kramer31 <kramer.newsreader@gmail.com> - 2011-04-07 17:09 -0700
  Re: Why only public methods on interfaces? Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2011-04-07 21:48 -0300
  Re: Why only public methods on interfaces? Joshua Cranmer <Pidgeot18@verizon.invalid> - 2011-04-07 21:01 -0400
    Re: Why only public methods on interfaces? v_borchert@despammed.com (Volker Borchert) - 2011-04-08 02:43 +0000
      Re: Why only public methods on interfaces? Joshua Cranmer <Pidgeot18@verizon.invalid> - 2011-04-08 00:24 -0400
  Re: Why only public methods on interfaces? Patricia Shanahan <pats@acm.org> - 2011-04-07 21:49 -0700
    Re: Why only public methods on interfaces? Owen Jacobson <angrybaldguy@gmail.com> - 2011-04-08 01:01 -0400
      Re: Why only public methods on interfaces? Patricia Shanahan <pats@acm.org> - 2011-04-07 22:37 -0700
        Re: Why only public methods on interfaces? Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> - 2011-04-08 00:14 -0700
          Re: Why only public methods on interfaces? Patricia Shanahan <pats@acm.org> - 2011-04-08 06:59 -0700
            Re: Why only public methods on interfaces? Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> - 2011-04-08 07:17 -0700
              Re: Why only public methods on interfaces? Patricia Shanahan <pats@acm.org> - 2011-04-08 08:59 -0700
                Re: Why only public methods on interfaces? Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> - 2011-04-08 17:27 -0700
                Re: Why only public methods on interfaces? "Mike Schilling" <mscottschilling@hotmail.com> - 2011-04-09 22:14 -0700
                Re: Why only public methods on interfaces? "Mike Schilling" <mscottschilling@hotmail.com> - 2011-04-09 22:28 -0700
                Re: Why only public methods on interfaces? Tom Anderson <twic@urchin.earth.li> - 2011-04-10 16:02 +0100
  Re: Why only public methods on interfaces? Roedy Green <see_website@mindprod.com.invalid> - 2011-04-08 03:18 -0700
    Re: Why only public methods on interfaces? Esmond Pitt <esmond.pitt@bigpond.com> - 2011-04-08 20:32 +1000
  Re: Why only public methods on interfaces? Tom Anderson <twic@urchin.earth.li> - 2011-04-08 20:34 +0100
  Re: Why only public methods on interfaces? Tom Anderson <twic@urchin.earth.li> - 2011-04-10 18:10 +0100

csiph-web