Re: Separate interface and implemenation problem..
Lew wrote:
Mark Space wrote:
// also not real code
public static interface MyRunnable {
static void run(); // implicitly public
}
Steven Simpson wrote:
But this marking seems unnecessary. Why does it matter that someone
implements MyRunnable non-statically? The user probably doesn't or
shouldn't (need to) care. If it matters to the implementation, let that
be it's [sic] own look-out.
Client code most
assuredly cares whether a method is static or instance-level. In the
former case it invokes the method via the type name; in the latter it
instantiates an owning object through which to invoke the method.
The "X implements static Y" clause means that an instance of something
implementing Y is available which maps its methods onto the static ones
on X. If you pass this instance to something else, it always invokes
with an instance call, and doesn't see the static call underneath.
The problem I have with the suggestion of a "static interface" is that
the suggestion to implement a static method in a concrete class
doesn't make sense. It's a very fundamental change to Java to have
"abstract static" methods.
I don't think I'm suggesting that. The type Y above is just an ordinary
interface type which another class could implement in the usual way with
instance methods.
To have a non-abstract static method in an interface violates the
intent that an interface be purely abstract.
Again, I'm not suggesting that. Y is an ordinary interface type with
abstract non-static methods.
Anyway, aren't global
variables and methods somewhat antithetical to the spirit of object-
orientation?
But they're not strictly global - it's just that, in normal use, the
context is implicit, as determined by static linking.
I've recently just realised there may be a simple way to implement
statically implemented interfaces (note, not "static interfaces" nor
"interfaces with static methods", but ordinary interfaces implemented
statically). I'll describe below, so it should be easier to discuss.
Suppose the compiler is given the following:
package org.example;
public class MyStaticExample implements static Runnable {
public static void run() { }
}
....so it generates two files, org/example/MyStaticExample.class as
usual, plus org/example/MyStaticExample$static.class as if from:
package org.example;
public final class MyStaticExample$static implements Runnable {
public void run() {
MyStaticExample.run();
}
}
A new method on java.lang.Class could then load this synthetic class with:
Class<?> getContractType() {
try {
return forName(getName() + "$static", false, getClassLoader());
} catch (ClassNotFoundException ex) {
return java.lang.Object.class;
}
}
The use of the same class loader should make sure that the synthetic
class's static reference to MyStaticExample is correctly bound to the
right, erm, thing that a Class instance reflects. (Well, actually,
there's surely a way to contrive failure here...)
Another new method on Class could just call
getContractType().newInstance(), and cache it for later calls:
private Object cachedContract;
public Object getContract() {
// notwithstanding concurrency issues
if (cachedContract == null)
cachedContract = getContractType().newInstance();
return cachedContract;
}
An expression such as org.example.MyStaticExample.static could be
converted to ((org.example.MyStaticExample$static)
org.example.MyStaticExample.class.getContractProxy()), so it would then
automatically have the right type for whatever it was assigned to.
new Thread(MyStaticExample.static)
....would become:
new Thread((MyStaticExample$static) MyStaticExample.class.getContractProxy())
The Thread constructor still gets a Runnable, and invokes it non-statically.
--
ss at comp dot lancs dot ac dot uk