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 19 Oct 2009 13:53 On Oct 19, 3:51 pm, Marcin Rze¼nicki <marcin.rzezni...(a)gmail.com> wrote: > On 19 Pa 1/4, 15:06, Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > > I'm saying it is wrong, but just don't like that the implementation > > requires a lot of reflection. (I don't mind that implementation of > > statndard Java API requires reflection, because someone has already > > implemented it for me. But if I want to create my own serialization > > framework (e.g. for xml serialization), I need to do a lot of > > reflection which could be automated.) Probably one thing I find wrong > > with readObject - as I already mentioned, it prevents the object to be > > immutable. Though this could also be solved by declaring it static and > > use reflection. > > Yes, but someone did it for you either - JAXB, xStreams etc. This is > not a type of work you do day-in day-out, so benefits are rarely to be > seen Occasionally new frameworks appear. Not an everyday work, but for me it justifies the introduction of a new feature, if there is no hidden danger we haven't noticed so far. I accept that for you it's not a sufficient reason. > > > > > Example with generics can easily be substituted by some kind of > > > > > "trait" parameter > > > > > Sorry, I don't know what you mean by "trait" parameter? Do you mean that > > > > I would call the zero() method on some instance? > > > > Like myDummyVector.zero()? > > > > I borrowed the terminology from C++. More or less, you add type > > > parameter (let's say <Zero extends ZeroVector>) which has a method > > > like getZeroVector() (strictly speaking ZeroVector has this method). > > > Actual type parameter provides concrete implementation. > > > I don't see how this would help. Would I call Zero.getZeroVector()? > > Probably you meant something else because this leads to the same > > problem with calling static method getZeroVector() on a type > > parameter. Could you provide an example? > > OK > public class MyVector<T, Zero extends ZeroVector> extends Vector2D<T> > { > ... > public MyVector(Zero zero) { this.zero = zero; } > ... > > } > > MyVector<Integer, Zero2D> vec = new MyVector(Vector2D.zero()); OK, but when we already resort to obtaining a zero vector from another instance, we don't need a reference to zero stored in each instance of vector. We can just have a nonstatic zero() method: abstract class Vector<T, V extends Vector<V>> { public abstract V zero(); } class Vector2D extends Vector<Integer, Vector2D> { public static final Vector2D ZERO = new Vector2D(0, 0); public Vector2D zero(){ return ZERO; } } I wanted to obtain zero without a reference to an instance. Using an instance is unnatural and sometimes an instance is just not at hand. > > > > > or suitable simple design pattern (for example > > > > > Factory), or even with classic sub-typing (zero vector needs not know > > > > > its dimension, it can simply 'answer' with neutral element of the ring > > > > > on which it is constructed for each and every component query), > > > > > Allowing operations between a concrete vector and this general zero > > > > vector would require to also allow operations between 2D and 3D vetors - > > > > the original type safety would disappear. > > > > I don't get it, could you provide an example? > > > If I understood well, you meant something like this: > > > Class Vector { > > public static Vector getZeroVector(){ > > return someSpecialZeroVectorInstance; > > } > > public abstract Vector add(Vector v); > > > } > > > Class Vector2D { > > public Vector add(Vector v){...} > > ... > > > } > > > class MyClass<V extends Vector> { > > ... > > V v; // V is some concrete class, such as Vector2D > > ... > > Vector zero = Vector.getZeroVector(); > > v.add(zero); // adding a general Vector zero to concrete v > > // if this is allowed, then also the following is > > v.add(new Vector3D(1,2,3)); // summing 2D and 3D vector > > ... > > > } > > Right but implementation of addition surely checks for this case, > doesn't it? Not necessarily: abstract class Vector<V extends Vector<V>> { public V add(V v); } class Vector2D extends Vector<Vector2D> { private final int x, y; public Vector2D(int x, int y){ this.x = x; this.y = y; } public Vector2D add(Vector2D v){ return new Vector2D(this.x + v.x, this.y + v.y); } } No checking that the argument of addition has the correct type, because this is enforced by the compiler. > public void add(Vector<? extends T> v) { if (v.getDimension() != > this.getDimension() ) throw new IllegalArgumentException(); } > So it suffices to have a factory method for appropriate zero vectors > Vector zero = Vector.getZeroVector(2); > > > > > > > > no big > > > > > win here either (eliminating type erasure is extremely welcome but for > > > > > other reasons). One big advantage of inheritance is, in my opinion, that > > > > > it enables you to compose more specialized classes from generic ones, it > > > > > is easy to imagine algebraic ordering relation between types based on > > > > > inheritance. Your version of statics breaks this assumption without > > > > > promise of any reward in exchange. > > > > > I don't see how it breaks this relation between classes. Also now it is > > > > possible to hide supertype's static methods by own implementation. I > > > > would only add that in some cases this hiding would be required. > > > > I was not very clear, it was late when I was writing :-) I guess what > > > I was trying to say was that you can impose ordering based on > > > specialization (as opposed to parent-child relationship). Each class > > > in an inheritance chain either extends or redefines partially its > > > ancestor (I am using 'or' as logical or). Therefore each class is > > > either more specialized (if redefinition occurs and it accepts > > > stronger contract, as in Rectangle->Square) or equally specialized (if > > > extension occurs and all redefinitions do not change contract - I > > > treat extension as an interface extension so that class can be used > > > _additionally_ in different context). Your proposal forces implementor > > > to provide implementation for non-inheritable method, so it really > > > can't take any benefit from redefinitions up the chain. Therefore all > > > concrete classes are at most equally specialized as their context of > > > usage is determined by a static method. So it does not play well with > > > most "inheritance patterns". That's how I see it. > > > Now I don't get it. Can you provide an example where you have a class > > and its specialized subclass and adding an abstract static method to > > their interface removes/prohibits this specialization? > > Yes, consider > public abstract class IOStream //for reading disk streams { > public abstract static boolean isReadable(File f) //returns true > for files which a concrete class can hopefully process. > ... > > } > > public class LocalIOStream extends IOstream { > public static boolean isreadable(File f) { return f.isLocalFile(); } > ... > > } > > public class AudioVideoStream extends LocalIOStream { > ??? > > } > > in AVStream you have, if I understood you correctly, two choices - > either to redo all work of super-classes which is not really an > option, let's say, > public static boolean isReadable(File f) { return f.isLocalFile() && > (f instanceof AudioFile && ((AudioFile)f).getAudioCodecID().equals > (...);} You don't have to redo the work, you can call the superclass's static method as usual: public static boolean isReadable(File f){ return LocalIOStream.isReadable(f) && f instanceof AudioFile && ((AudioFile)f).getAudioCodecID().equals(...); } Furthermore, if we expect that specialized IOStreams will only be able to process instances specialized instances of File, the IOStreams could be parametrized by the type of the File. abstract class IOStream<F extends File> { public abstract static boolean isReadable(F f); } class LocalIOStream<F extends File> extends IOStream<F> { public static boolean isReadable(F f){ return f.isLocalFile(); } } class AudioVideoStream extends LocalIOStream<AudioFile> { public static boolean isReadable(AudioFile f){ return LocalIOStream.isReadable(f) && f.getAudioCodecID().equals(...); } } > or omit it so then you impose different context. Namely, pretend to be > able to read remote files while you are not. > And one more question: > //client code > Stream s = new AudioVideStream(..); > read10Bytes(s); > > public byte[] read10Bytes(Stream s) { > if (!Stream.isReadable(file)) //how would you dispatch it? There is no > way I suppose > > } This would be a compile-time error, since isReadable() is abstract in Stream.
From: Eric Sosman on 19 Oct 2009 14:11 Andreas Leitgeb wrote: > Eric Sosman <Eric.Sosman(a)sun.com> wrote: >> Andreas Leitgeb wrote: >>> I still see some merit in being able to enforce that any concrete >>> class implementing some thusly declared interface had to offer some >>> particular c'tor, as a means to help developers of such classes to >>> not forget about it. > >> Here's my objection: Suppose there's an Entertainer interface >> (or abstract class) and ... >> ... >> Okay, it might make sense for the class of Comedians to have a >> default stale Joke (a faithful model of reality, perhaps), ... > :-) >> ... >> The author of Entertainer, who knew nothing about the wants and needs >> of those who would come later, ... > > Thanks for the entertaining example, but I think it's beside the point. > This type of argument "it's bad for this exemplary usecase, so it must > be bad for all usecases" is obviously flawed. (or was a joke, itself) "Bad for one, bad for all" -- Sounds like _Les Trois Mousquetaires_, non? But the point of my (rather whimsical) illustration is that I think "specialization" is the principal motivation for subclassing, and that the situation I describe is not just one isolated oddity but quite common. The specialized subclass quite often has attributes not shared with the superclass or interface, and those attributes are frequently modeled by instance variables. If the instance variables need non-default values for the instance to be "functional," a logical way to provide those values is through the constructor. An external mandate that requires a non-constructor route for initializing the values seems to do little more than force the programmer to jump through unnecessary hoops: Dream up defaults even when none suggest themselves, provide setters (and give up `final'), throw IllegalStateException all over the place ... All just so the @#$!*!! mandate can be satisfied. > On second thought: If the Entertainers were designed to be dynamically > loaded by name, then Comedians just wouldn't have any chance of a individual > default joke. They could offer their Joke- constructor, but unless they > also offered a no-args one, they just wouldn't ever be successfully engaged. I'm not sure why the second sentence follows from the first: Once you've got the Class object, you can surely use getConstructors() on it, can you not? And if you know enough to be able to supply a Joke to a post-construction setter, why couldn't you just as well hand it to a Constructor's newInstance() method? But I admit that my familiarity with frameworks of this kind is slight. Perhaps they're just not suited for classes whose instances lack obvious defaults. (Maybe they're only good for singletons?) -- Eric.Sosman(a)sun.com
From: Tomas Mikula on 19 Oct 2009 14:25 On Oct 19, 4:13 pm, Andreas Leitgeb <a...(a)gamma.logic.tuwien.ac.at> wrote: > Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > > On Mon, 19 Oct 2009 07:29:24 +0000, Andreas Leitgeb wrote: > >> Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > >>> presence of no-arg constructor in a serializable class would be checked > >>> at compile-time rather than at run-time. > >> I think this is easily misunderstood. The newly possible compiletime > >> check would be for compiling the *concrete class* whose name you later > >> intend to specify dynamically at runtime. This does have some merit. > > >> Still no compiletime check would of course be possible at the place > >> where you'd *use* that class dynamically, so nothing at all can be > >> helped about the reflection-part of this story. > > > The idea here was to automate the reflection. > > Sorry, that is a non-starter. > > If you know the class at compiletime, you can just use it with > the "new"-operator and have all kinds of compile time checks. > > If you don't know the class at compiletime, then neither does the > compiler, so there's nothing the compiler could possibly do for you > beyond what it already does, namely write bytecode to have the JVM > check it all at runtime. In my original post I noted that the use of Class's newly introduced method <T> Implementation<T> asImplementationOf(Class<T> clazz); would have the restriction that the type T is known at compile time. In this case, the compiler can generate the bytecode to check if the 'this' class implements T. > Even at runtime, there's no saving: both, interface and existence > of relevant methods and constructors, each have to be checked > separately by the JVM. Although my major intention was to reduce writing reflective code, there could also be a run-time saving: as soon as the JVM loads a class A, it will know if it 'statically implements' interface J. (By the same mechanism as it knows if A implements interface I.) 'Statically implements' would just be a new kind of relationship between classes, in addition to 'extends' and 'implements'. > > I still see some merit in being able to enforce that any concrete > class implementing some thusly declared interface had to offer some > particular c'tor, as a means to help developers of such classes to > not forget about it. > > About the static methods: if you need that kind of enforcement for > dynamically used classes, then just use instances and non-static > methods as helpers: > > public interface Foo { // known to the user at compiletime. > public void pseudoStatic();} > > public class FooBar { // known to the user only at runtime > public void pseudoStatic() { realStatic(); } > public static void realStatic() { /* do something ... */ }} > > // snippet of user's code: > Foo x = (Foo)use_reflection_to_get_instance(implName); // implName=="FooBar" > x.pseudoStatic(); > > Up to minor syntactical differences this FooBar object does what your > ".asImplementationOf()" result was intended to do, if I understood it > correctly. Yes, but: - it requires to get an unnecessary instance (not so bad yet); - getting this instance requires reflection - using reflection for getting an instance requires conventions which cannot be checked at runtime (such as the presence of some particular (e.g. no-arg) constructor) If I'm interested in just one static method, it turns out I could just use reflection to get this Method instead of a dummy instance. Furthermore, if I forget to override pseudoStatic() or realStatic() in a subclass, I will get the realStatic() from superclass, which is not what I want. The compiler will not enforce me in any way to override them. > I don't think, that calling static methods on dynamically > named classes is worth such deep changes as you seem to have in mind > for this task. The good thing about it is that the changes are not real changes, just extensions. So far I think they are all backward compatible with current specification. No old code would be broken if these extensions are introduced.
From: Marcin Rzeźnicki on 19 Oct 2009 14:37 On 19 Pa¼, 19:53, Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > On Oct 19, 3:51 pm, Marcin Rze 1/4 nicki <marcin.rzezni...(a)gmail.com> > wrote: > > > On 19 Pa 1/4, 15:06, Tomas Mikula <tomas.mik...(a)gmail.com> wrote: > > > I'm saying it is wrong, but just don't like that the implementation > > > requires a lot of reflection. (I don't mind that implementation of > > > statndard Java API requires reflection, because someone has already > > > implemented it for me. But if I want to create my own serialization > > > framework (e.g. for xml serialization), I need to do a lot of > > > reflection which could be automated.) Probably one thing I find wrong > > > with readObject - as I already mentioned, it prevents the object to be > > > immutable. Though this could also be solved by declaring it static and > > > use reflection. > > > Yes, but someone did it for you either - JAXB, xStreams etc. This is > > not a type of work you do day-in day-out, so benefits are rarely to be > > seen > > Occasionally new frameworks appear. Not an everyday work, but for me > it justifies the introduction of a new feature, if there is no hidden > danger we haven't noticed so far. I accept that for you it's not a > sufficient reason. > It is, but I am trying to bring up some dangers of your method throughout this thread. > > > > > > > > Example with generics can easily be substituted by some kind of > > > > > > "trait" parameter > > > > > > Sorry, I don't know what you mean by "trait" parameter? Do you mean that > > > > > I would call the zero() method on some instance? > > > > > Like myDummyVector.zero()? > > > > > I borrowed the terminology from C++. More or less, you add type > > > > parameter (let's say <Zero extends ZeroVector>) which has a method > > > > like getZeroVector() (strictly speaking ZeroVector has this method).. > > > > Actual type parameter provides concrete implementation. > > > > I don't see how this would help. Would I call Zero.getZeroVector()? > > > Probably you meant something else because this leads to the same > > > problem with calling static method getZeroVector() on a type > > > parameter. Could you provide an example? > > > OK > > public class MyVector<T, Zero extends ZeroVector> extends Vector2D<T> > > { > > ... > > public MyVector(Zero zero) { this.zero = zero; } > > ... > > > } > > > MyVector<Integer, Zero2D> vec = new MyVector(Vector2D.zero()); > > OK, but when we already resort to obtaining a zero vector from another > instance, we don't need a reference to zero stored in each instance of > vector. We can just have a nonstatic zero() method: > > abstract class Vector<T, V extends Vector<V>> { > public abstract V zero(); > > } > > class Vector2D extends Vector<Integer, Vector2D> { > public static final Vector2D ZERO = new Vector2D(0, 0); > public Vector2D zero(){ return ZERO; } > > } > > I wanted to obtain zero without a reference to an instance. Using an > instance is unnatural and sometimes an instance is just not at hand. > > Right, but that was just an example of what is 'trait'. I am not saying this is necessarily the best design decision in this case. > > > Right but implementation of addition surely checks for this case, > > doesn't it? > > Not necessarily: > > abstract class Vector<V extends Vector<V>> { > public V add(V v); > > } > > class Vector2D extends Vector<Vector2D> { > private final int x, y; > public Vector2D(int x, int y){ this.x = x; this.y = y; } > public Vector2D add(Vector2D v){ > return new Vector2D(this.x + v.x, this.y + v.y); > } > > } > > No checking that the argument of addition has the correct type, > because this is enforced by the compiler. > > Formal arguments have to be invariant with respect to overriding in Java, you simply created method overload which will be used when compiler is sure that runtime type of argument will be Vector2D. You will still have to provide 'generic' add method. Your example does not help either (or I cannot see how it would) because you will not be able to dispatch on v's actual type unless you change how invokestatic works. > > > Yes, consider > > public abstract class IOStream //for reading disk streams { > > public abstract static boolean isReadable(File f) //returns true > > for files which a concrete class can hopefully process. > > ... > > > } > > > public class LocalIOStream extends IOstream { > > public static boolean isreadable(File f) { return f.isLocalFile(); } > > ... > > > } > > > public class AudioVideoStream extends LocalIOStream { > > ??? > > > } > > > in AVStream you have, if I understood you correctly, two choices - > > either to redo all work of super-classes which is not really an > > option, let's say, > > public static boolean isReadable(File f) { return f.isLocalFile() && > > (f instanceof AudioFile && ((AudioFile)f).getAudioCodecID().equals > > (...);} > > You don't have to redo the work, you can call the superclass's static > method as usual: > > public static boolean isReadable(File f){ > return LocalIOStream.isReadable(f) && > f instanceof AudioFile && > ((AudioFile)f).getAudioCodecID().equals(...); > > } Yeah, right, but consider what happens when someone implements multiple interfaces, or when inheritance tree changes, or when someone inherits multiple interfaces with conflicting statics and so on. This example is basically hand-crafted implementation of virtual dispatch :-) > > Furthermore, if we expect that specialized IOStreams will only be able > to process instances specialized instances of File, the IOStreams > could be parametrized by the type of the File. > > abstract class IOStream<F extends File> { > public abstract static boolean isReadable(F f); > > } > > class LocalIOStream<F extends File> extends IOStream<F> { > public static boolean isReadable(F f){ > return f.isLocalFile(); > } > > } > > class AudioVideoStream extends LocalIOStream<AudioFile> { > public static boolean isReadable(AudioFile f){ > return LocalIOStream.isReadable(f) > && f.getAudioCodecID().equals(...); > } > > } Well, ok, but it does not change anything. Still you have to re- implement invokevirtual by hand all the time :-) > > or omit it so then you impose different context. Namely, pretend to be > > able to read remote files while you are not. > > And one more question: > > //client code > > Stream s = new AudioVideStream(..); > > read10Bytes(s); > > > public byte[] read10Bytes(Stream s) { > > if (!Stream.isReadable(file)) //how would you dispatch it? There is no > > way I suppose > > > } > > This would be a compile-time error, since isReadable() is abstract in > Stream. This is really bad :-) Then actually your statics will be usable only when you know exact type you want to work with.
From: Steven Simpson on 19 Oct 2009 14:26
Joshua Cranmer wrote: > On 10/18/2009 10:06 PM, Tomas Mikula wrote: >> I have searched this group for "abstract static methods" and found a >> couple of threads, [...] > > I saw a more detailed proposal at <http://kijaro.dev.java.net>, which > included a prototype implementation. ....which we didn't complete, btw. The bits missing (described below) are: * the generation of X$static, * the expansion of X.static, * verification of classes claiming to 'implement static' interfaces. So, just the important bits! ;-) I have no idea how to proceed with those (lack of familiarity with javac internals), and Stefan was not optimistic about the feature's prospects (so understandably he didn't want to put much more effort into it). > The specification for said stuff is linked here: > <http://www.jroller.com/jadda/entry/meta_interfaces_revisited>. I shall summarize here, as the plan below is not expected to achieve as much as all the ideas discussed in the blog. The current plan is to support 'static' on the implementation of whole interfaces, rather than on individual methods. Given a class such as: class X implements static Runnable { public static void run() { ... } } ....then you could write X.static, and get a normal Runnable on which you could invoke run(), and it would actually invoke X.run(). If X was loaded dynamically, you could get the same Runnable: Class<?> clazz = Class.forName("X"); if (clazz.meetsContract(Runnable.class)) { Runnable r = clazz.contractOn(Runnable.class); ... } So you can invoke a static method on the dynamically loaded class without method reflection. And X can be checked at compile-time that it provides required static methods. It would work by the compiler generating an extra class when it saw 'implements static'. For X, that would be: class X$static implements Runnable { public void run() { X.run(); } } Each Class object would have a proxy object (created on demand), which would be an instance of X$static in this case. By being loaded with the same ClassLoader as X, the X.run() call would bind to the correct X#run() static method. 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. Maybe the OP could check whether his requirements would be met by such a feature. It might fall short, but when problems are expressed as a lack of static interface methods, I usually start thinking of defining regular interfaces with the necessary methods (e.g. abstract factories), and end up with something more powerful anyway (e.g. decoupled construction and use of a class). The 'implements static' feature is just a way of doing such things as factories without needing to overtly create a 'dummy' factory object. Cheers! -- ss at comp dot lancs dot ac dot uk |