Prev: Java work from home. Remote (telecommuting) jobs in Java.
Next: Zip question: Where are all the extra characters coming fromupon unzipping?
From: Tomas Mikula on 21 Oct 2009 08:35 On Tue, 20 Oct 2009 20:17:19 -0400, Lew wrote: > Tomas Mikula wrote: >> 2. For calling static methods on generics. My example was abstract >> class Vector<V extends Vector<V>>{ >> /** returns a zero vector */ >> public abstract static V zero(); >> } > > This would be an extreme change to the semantics of Java generics, most > likely very infeasible as stated. Type parameters are resolved per > instance, and do not apply class-wide. > > How is it even possible for a class to know what type to use for 'V', > when every instance of that class could have a different type > replacement for it? Whenever you have an instance myObj of class MyClass<V>, the instance would know the type of V (it is not true now, but hopefully will be true someday in the future). Now if you call a method on myObj that calls a static method (or constructor) on V, the method lookup would be done with aid of myObj. If static means resolved at compile time, then yes, this is against the nature of static. I don't know how difficult it would be to implement, I just suggested it is feasible (and IMO useful). And for the sake of completeness, if you have a generic method parametrized by T, then it takes some parameter whose instance will know the actual type of T. So again you have an instance to help to resolve the T's static method/constructor.
From: Eric Sosman on 21 Oct 2009 08:50 Tomas Mikula wrote: > On Tue, 20 Oct 2009 18:28:45 -0400, Eric Sosman wrote: > >> Daniel Pitts wrote: >>> Eric Sosman wrote: >>>> Tomas Mikula wrote: >>>>> [...] >>>>> 1. serialization frameworks. It is already required that a >>>>> Serializable class has a no-arg constructor. But this is not required >>>>> at compile time. >>>> You've said this a couple times, but are you sure it's true? >>>> This class (with no no-arg constructor) appears to serialize and >>>> deserialize just fine: >>> Only the non-Serializable Base of a Serializable class requires a >>> no-args constructor: [...] > > Ah, I was wrong with this. But this only means that the Java's > serialization doesn't use _any_ constructor to create an object. It uses the no-args constructor for any non-Serializable superclass of the object being deserialized. Since Object is not Serializable, it follows that deserialization always invokes at least one no-args constructor. But it doesn't invoke any constructor for the "direct" object itself, no. > Which > means that it uses some tricks not available to the programmer (correct > me if I am wrong). Right. Among other things, the JVM may invoke private methods (readObject, for example) of the Serializable class. You couldn't do that from outside the class, not even by writing bytecode instead of Java. > In your own serialization framework you would need to > create the object being deserialized, so you would care about the > constructors available on your class, not the superclass. If you want to implement your own scheme for pickling and reconstituting objects, others have suggested factory methods and/or auxiliary "builder" objects. That might improve the case for abstract static methods, but I still don't see it as a persuasive argument for abstract constructors. YMMV. -- Eric Sosman esosman(a)ieee-dot-org.invalid
From: Tomas Mikula on 21 Oct 2009 10:26 On Wed, 21 Oct 2009 06:10:02 +0100, Steven Simpson wrote: > Tomas Mikula wrote: >> On Mon, 19 Oct 2009 19:26:41 +0100, Steven Simpson wrote: >> >>> class X implements static Runnable { >>> public static void run() { ... } >>> } >>> >>> >> Now if you had >> >> class Y extends X {...} >> >> would the compiler enforce that Y provides its own implementation of >> static run() method? (My desirable answer would be YES.) >> >> > My initial answer is 'no'. Y$static would contain: > > public void run() { > Y.run(); > } > > ...which would just bind to X#run() if Y didn't provide its own #run(). > > However, I guess the compiler could enforce it, though I'm not sure if > one would want that in all situations. In its favour, while Y instances > might inherit behaviour available in X instances due to 'Y extends X', > there's no reason for the static aspect of Y to inherit the static > aspect of X, e.g. it does not necessarily follow that Y$static extends > X$static, or that (X implements static Runnable && Y extends X => Y > implements static Runnable). Hmm... > >> If you had an abstract class >> abstract class X implements static Runnable {...}, would the >> implementation of static method run() still be required? (My desirable >> answer would be NO.) >> >> > I would say 'yes', if only since 'abstract' has never affected static > methods. It's true that it is mixing of notions. I mean something like 'abstract with respect to static'. Maybe requiring both kinds of abstract to always appear simultaneously isn't the best idea. Maybe this kind of abstract could instead be denoted as 'implements abstract static' :) > In fact, since you expect (from the previous question) that any Y which > extends X must provide its own static run(), I don't see a point in > requiring X to 'implements static Runnable' if it's only going to leave > the implementation to a base class. The point would be to enforce the subclasses to 'implement static' Runnable. Consider again an abstract class Vector with static method zero(), which should return a zero vector. Vector alone doesn't need (even can't reasonably) implement zero(), but it wants to enforce its implementation in all concrete subclasses. > > For instance methods, where Y extends X, it's clear that having an X > reference could mean invoking a Y object, i.e. you have a piece of code > which syntactically only refers to type X but semantically could invoke > Y: > > abstract class X { public abstract void doSomething(); } class Y extends > X { ... } > > X ref = ...; > ref.doSomething(); // this piece > > At run-time, you might be dealing with Y, but statically you have only > X. When do you have an analogous case for static methods? I don't want to have an analog for static methods. If X 'implements abstract static' Runnable, I wouldn't want to be able to call X.run() or X.static.run(). > In the dynamic-loading use-case, Y would be explicitly identified by > name (and passed to Class#forName(String)). You then check dynamically > that Y 'implements static Runnable' with a call to > Class#meetsContract(Runnable.class). Anything you say about X is > irrelevant. Agreed. > In the reified-generics case, you might have a class that requires a > type parameter that 'implements static Runnable': > > class Banana<T extends static Runnable> { > { > T.run(); > } > } > > (Aside: I don't see a point in distinguishing between 'extends' and > 'implements' on a type parameter, as only one relationship needs to be > expressed, i.e. Class#isAssignableFrom(Class), which is the same whether > you're dealing with interfaces or classes.) By 'implements' I meant what you mean by 'extends static'. I just needed to distinguish it from 'extends' without introducing new keyword. > Then you write 'new Banana<Y>', and the compiler checks that Y > 'implements static Runnable', and still X is not involved. > > Can you write an example where some code statically uses X and that it > 'implements static Runnable', but could actually end up invoking > Y#run()? I can't. This was not my intention. On the other hand my intention was that even when you call Y#run() you cannot end up invoking X#run(). >>> It would work by the compiler generating an extra class when it saw >>> 'implements static'. >>> >>> >> Somehow I feel that for consistency any class should support X.static, >> not just when it 'implements static' some interface. > > Yes. For classes without any 'implements static', the proxy object that > X.static ultimately evaluates to (and which Class#getContractor() > returns) can just be an instance of Object, as there are no interfaces > that it has to conform to. My intuition was that X.static should allow to invoke any static method of X, not just the ones that appear in some interface that X statically implements: class X implements static Runnable { public static void run(){...} public static void another(){...} } X.static.another(). Not that this would be of any use, it just would feel natural. But then you would need to generate X$static class for every class that has a static method. >> But I'm curious what was the motivation for having X.static? > > If nothing else, just to ensure that there is a static, type-safe, > compile-time way to obtain the proxy object. If you happen to know X > statically, and that 'X implements static Z', and something accepted a > Z, you could write doSomething(X.static). As you said, X.static is a comfortable way to call (X$static) X.class.getContractor(). Though in every concrete use it could be replaced by X.class.contractOn(SomeInterface.class). X.static is nice and concise, but IMO omitting it (and Class.getContractor ()) avoids some problems (if you agree that X.static should support all X's static methods) without using much usefulness. >> I only see usability if it was >> allowed to use it on type parameters: >> >> class MyClass<T static implements Runnable> { >> ... >> T.static.run(); >> ... >> } >> >> > As you noted before, this sort of thing seems to require reification, > though it's pretty similar to something in Stefan's last topical blog > entry, where he felt that something could be done without reification. I will yet need to look at it. >>> An expression such as: >>> >>> X.static >>> >>> ...would expand to: >>> >>> (X$static) X.class.getContractor() >>> >>> Class#getContractor() would create the proxy or recover a cached one. >>> >>> >> Or maybe X.static could just expand to X._static where the line >> >> public static final X$static _static = new X$static(); >> >> would be added to class X. >> >> > Good idea, though I don't think '_static' is an especially reserved name > (is it?). 'static' would never clash with any real class member, and > we're past syntactic analysis by now, so it should be expressible in > bytecode. Then X.static could just expand to X.static, or? > One problem might be that Class#getContractor() would have to > reflectively look-up a static field on X, instead of just calling > Class.forName("X$static").newInstance(). Was there any other useful use of Class#getContractor() other than with resolving X.static? If it now was not necessary for that, getContractor could be omitted completely. > Also, there was an objection to increased object count, so creating on > demand seemed worthwhile. I admit. So, to sum up, the intersection of our ideas seems to be adding method <T> T contractOn(Class<T> clazz); to class Class. This could be implemented as follows: <T> T contractOn(Class<T> clazz){ return clazz.cast(Class.forName(this.getName() + "$static").newInstance()); } But we diverge on the opinion for what classes X there should be class X $static. You say that only for classes that explicitely state 'implements static', I say that also for all their subclasses. Further, we diverge on whether Y$static could end up invoking X's static methods.
From: Lew on 21 Oct 2009 11:30 Lew wrote: >> How is it even possible for a class to know what type to use for 'V', >> when every instance of that class could have a different type >> replacement for it? > Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > Whenever you have an instance myObj of class MyClass<V>, the instance > would know the type of V (it is not true now, but hopefully will be true > someday in the future). Now if you call a method on myObj that calls a > static method (or constructor) on V, the method lookup would be done with > aid of myObj. If static means resolved at compile time, then yes, this is > against the nature of static. I don't know how difficult it would be to > implement, I just suggested it is feasible (and IMO useful). > Isn't that a violation of the fundamental semantic of 'static' as "class-wide, does not use an instance to resolve"? (Yes, it is.) This is not a compile-time vs. run-time matter, despite your attempt at misdirection. The semantic of 'static' applies at run time and compile time, both. It means "class level". You suggest using an instance-level semantic to resolve the meaning of a 'static' construct. That is too fundamental a change. -- Lew
From: Tomas Mikula on 21 Oct 2009 11:59
On Wed, 21 Oct 2009 08:30:38 -0700, Lew wrote: > Lew wrote: >>> How is it even possible for a class to know what type to use for 'V', >>> when every instance of that class could have a different type >>> replacement for it? >> >> > Tomas Mikula <tomas.mik...(a)gmail.com> wrote: >> Whenever you have an instance myObj of class MyClass<V>, the instance >> would know the type of V (it is not true now, but hopefully will be >> true someday in the future). Now if you call a method on myObj that >> calls a static method (or constructor) on V, the method lookup would be >> done with aid of myObj. If static means resolved at compile time, then >> yes, this is against the nature of static. I don't know how difficult >> it would be to implement, I just suggested it is feasible (and IMO >> useful). >> >> > Isn't that a violation of the fundamental semantic of 'static' as > "class-wide, does not use an instance to resolve"? > > (Yes, it is.) > > This is not a compile-time vs. run-time matter, despite your attempt at > misdirection. The semantic of 'static' applies at run time and compile > time, both. It means "class level". You suggest using an > instance-level semantic to resolve the meaning of a 'static' construct. > That is too fundamental a change. I will just note that it would be using an instance of a different class than whose static method is called. This instance would be used to obtain the class. After that, the invocation of it's static method would not use any instance-level semantics. The code class MyClass<V extends Vector<V>> { void doSomething(){ V v = V.zero(); } } could be translated to something like class MyClass<V extends Vector<V>> { void doSomething(){ // get the class (uses an instance of MyClass, namely 'this') Class<V> clazz = Class.getTypeParameterClass(this, "V"); // invoke the static method (no instance of V used) V v = clazz.getMethod("zero").invoke(null); } } |