Re: abstract static methods (again)
On 20 Pa=C5=BA, 00:29, Tomas Mikula <tomas.mik...@gmail.com> wrote:
On Mon, 19 Oct 2009 11:37:07 -0700, Marcin Rze=C5=BAnicki wrote:
On 19 Pa=C5=BA, 19:53, Tomas Mikula <tomas.mik...@gmail.com> wrote:
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, becaus=
e
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.
No. Notice how add() is declared in Vector:
public V add(V v);
It works on type V.
When Vector2D is declared as
Vector2D extends Vector<Vector2D>,
Vector2D is substituted for V. So Vector2D's add() method is only
required to work on Vector2D instances. If Vector2D was declared as
Vector2D<V extends Vector<V>> extends Vector<V>,
then Vector2D would have to implement the add() method that takes any
subclass of Vector and returns the same subclass of Vector as it takes.
Sorry, I did not notice - compiler probably is bound to generate
bridge method which makes cast to Vector2D
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=
..
I'm not sure if I understand, but in the implementation of Vector2D V is
bound to Vector2D at compile time.
But I am free to pass an instance of any conforming type.
Yes, consider
public abstract class IOStream //for reading disk streams {
public abstract static boolean isReadable(File f) //ret=
urns 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).getAudioCodec=
ID().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.
Right now I can't think of any problems different from those with non-
static methods.
Except that super calls are dispatched by VM with no help needed from
a programmer.
This example is
basically hand-crafted implementation of virtual dispatch :-)
...
Well, ok, but it does not change anything. Still you have to re-
implement invokevirtual by hand all the time :-)
Well, if you want to extend the behavior of a non-static method, you
still have to call the inherited method by hand (super.someMethod()) and
then do your specific work. This is no different from my example. The
only real disadvantage is when you want to inherit the method as is. Yes,
this is not possible with my proposal and you have to call the
superclass's method by hand. Though my proposal was targeted at uses
where you want to provide own implementation in each class. But I'm
finally getting what you are trying to say - that this feature might
encourage design that will later turn out as wrong. Yes, there might be
this danger, as is with many other features.
Right, but the difference is that super calls are not subject to
'human' errors (what happens if inheritance chain has been updated?
you have to manually review all subclasses and repair static calls)
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.
And with generics and with dynamic loading.
Still, you have to redefine static method so that it is _usable_ for
every type, but _used_ only when exact type is of special interest
which encourages too strict typing. Ok, probably now I understand
fully your concept. I'd uphold my opinion that this is not so good.
Here is a quick rundown why I think so:
1. Problem it solves can be solved in other ways, without any need for
special syntax/semantics/language or VM changes (like Vector)
2. It is not clear how it would/should behave even for problems it is
supposed to solve
(code: public <T extends Foo> void doSth(T t) { T.staticFromFoo(); }
public class Bar extends Foo { public static void staticFromFoo()
{...};}
what should it bind to? If Foo, what if it is passed a Bar instance in
runtime?)
3. It encourages bad code smell, that is: coding with the most
specific type instead of coding with interfaces
4. It solves relatively infrequent problems
5. It is error prone - developers will have to study all subclasses to
spot what should be changed after any superclass has changed
6. It makes developers implement this static heritage over and over,
even when it is not needed
Please clarify if I am wrong somewhere.