can this be done with generics?

A

Andreas Leitgeb

I'd like to use the "call methods in a chain" pattern
across a class-subhierarchy, with most of the methods
defined in the base-class.

Suppose, I had two classes:

class Foo {
public Foo foo1() {
/* do something very interesting ... */
return this;
}
// assume there were like 100 such foo#() methods here
// (in practice they of course have more diverse names)
}
class Bar extends Foo {
public Bar bar() {
/* do something very interesting */
return this;
}
}

And then, somewhere else:

// the single-class chain works just fine:
new Foo().foo1().foo42().foo84();

// but if I start with a Bar, and eventually after some foo#() calls
// want to call method bar() which is not in Foo, then I'm out of luck:
new Bar().foo1().foo42().foo84().bar(); // doesn't work, of course!

Is there a way to use *generics* for the methods of class Foo such that
each foo#() returns the *static* type on which the compiler saw it
applied?

Alternatives, that do NOT satisfy me:
a) use an explicit cast to (Bar)
((Bar)(new Bar().foo1().foo42().foo84())).bar();
Would turn into a nightmare, when more of Bar's
methods got mixed into the chain.
b) override each of the 100 foo#()s in Bar with a Bar return-type.
Would turn into a nightmare, when more sub-classes like Bar
appeared, or new methods added to Foo.
(Note, that "bad performance" due to extra calls is NOT my concern here)
c) add "Foo bar() { return this; }" in Foo.
Would turn into a nightmare, when more sub-classes like Bar
appeared (and Foo would have to reflect all subclasses' methods),
or some chain accidentally called a subclass method on a chain
started from some other class's instance, and compiler wouldn't
detect the mistake.

I'm pretty sure, that this would be principially possible (as in: the
compiler has all the information that would be needed), but I can't seem
to find an approach for how to capture the static type of the expression
on which the (non-static) method is called.

Thanks in advance!
 
A

Arne Vajhøj

I'd like to use the "call methods in a chain" pattern
across a class-subhierarchy, with most of the methods
defined in the base-class.

Suppose, I had two classes:

class Foo {
public Foo foo1() {
/* do something very interesting ... */
return this;
}
// assume there were like 100 such foo#() methods here
// (in practice they of course have more diverse names)
}
class Bar extends Foo {
public Bar bar() {
/* do something very interesting */
return this;
}
}

And then, somewhere else:

// the single-class chain works just fine:
new Foo().foo1().foo42().foo84();

// but if I start with a Bar, and eventually after some foo#() calls
// want to call method bar() which is not in Foo, then I'm out of luck:
new Bar().foo1().foo42().foo84().bar(); // doesn't work, of course!

Is there a way to use *generics* for the methods of class Foo such that
each foo#() returns the *static* type on which the compiler saw it
applied?
I'm pretty sure, that this would be principially possible (as in: the
compiler has all the information that would be needed), but I can't seem
to find an approach for how to capture the static type of the expression
on which the (non-static) method is called.

I don't think it is possible. Java is a static typed language and even
though that in your code example the compiler could detect that the
object is a Bar object, then in most code sequences that would
not be the case.

void bad(Foo o) {
o.foo1().bar():
}

Does o have a bar or not?

If you want to code like this you need dynamic typed language.

Arne
 
S

Saxo

If you want to code like this you need dynamic typed language.

Yes, that's right. Or you need a semi-typed language like Objective-C whereyou can do things exactly as intended in your port. Objective-C has a special type named "id", which will be of the type at runtime of the object returned at runtime. The Objective-C will issue a warning when you return an object of type id and leave things to your responsability whether things will work well.

There is also Fantom on the JVM that has that feature as Objective-C. In Scala you can get this accomplished through the use of implicits (see this article: http://objectscape.blogspot.de/2013/08/scala-implicits-conversion-on-steroids.html). But you may run into problems that things become hard to read when you use too many implicits. But for Java it can't be done as for any statically typed language that does not have holes in its typing system.

Cheers, Saxo
 
S

Saxo

Am Montag, 25. November 2013 10:43:07 UTC+1 schrieb Saxo:
Yes, that's right. Or you need a semi-typed language like Objective-C where you can do things exactly as intended in your port. Objective-C has a special type named "id", which will be of the type at runtime of the object returned at runtime. The Objective-C will issue a warning when you return anobject of type id and leave things to your responsability whether things will work well.



There is also Fantom on the JVM that has that feature as Objective-C. In Scala you can get this accomplished through the use of implicits (see this article: http://objectscape.blogspot.de/2013/08/scala-implicits-conversion-on-steroids.html). But you may run into problems that things become hard toread when you use too many implicits. But for Java it can't be done as forany statically typed language that does not have holes in its typing system.



Cheers, Saxo

I forgot: Think it can be done in Ceylon (ceylon-lang.org). Ceylon has a special feature that can be used in that way. Lets say you have a class A with a method foo() and a class B, which is a subclass of A and also has a method foo(). If I remember right in Ceylon A.foo() and B.foo() may have different return types. But this is the only statitcally type OOPL I know of that can do this.
 
S

Silvio

I don't think it is possible. Java is a static typed language and even
though that in your code example the compiler could detect that the
object is a Bar object, then in most code sequences that would
not be the case.

void bad(Foo o) {
o.foo1().bar():
}

Does o have a bar or not?

If you want to code like this you need dynamic typed language.

Arne

The OP says nothing about doing the call on a reference of type Foo. In
fact, he explicitly talks about the compiler having all the information
needed.

This can be done in Scala where you can have a return type "this.type"
which means the compiler will consider as the return type the type of
the reference the call is made on, even if the method is defined in a
base class.
 
S

Saxo

The OP says nothing about doing the call on a reference of type Foo. In
fact, he explicitly talks about the compiler having all the information
needed.

Oh, my fault. Should have spent more time reading the post ...
This can be done in Scala where you can have a return type "this.type"
which means the compiler will consider as the return type the type of
the reference the call is made on, even if the method is defined in a
base class.

Interesting. Didn't know that. Thanks.
 
A

Andreas Leitgeb

Silvio said:
I'd like to use the "call methods in a chain" pattern
across a class-subhierarchy, with most of the methods
defined in the base-class.
[...]
Is there a way to use *generics* for the methods of class Foo such that
each foo#() returns the *static* type on which the compiler saw it
applied?

The OP says nothing about doing the call on a reference of type Foo. In
fact, he explicitly talks about the compiler having all the information
needed.

Thanks for understanding me :)
This can be done in Scala where you can have a return type "this.type"
which means the compiler will consider as the return type the type of
the reference the call is made on, even if the method is defined in a
base class.

Interesting to see that the concept at least exists in some language.

For my task, though, I'll probably have to choose one of the less-than-
satisfying alternatives. :(
 
P

Patrick Roemer

Responding to Andreas Leitgeb:
class Foo {
public Foo foo1() {
/* do something very interesting ... */
return this;
}
// assume there were like 100 such foo#() methods here
// (in practice they of course have more diverse names)
}
class Bar extends Foo {
public Bar bar() {
/* do something very interesting */
return this;
}
} [...]
// but if I start with a Bar, and eventually after some foo#() calls
// want to call method bar() which is not in Foo, then I'm out of luck:
new Bar().foo1().foo42().foo84().bar(); // doesn't work, of course!

Is there a way to use *generics* for the methods of class Foo such that
each foo#() returns the *static* type on which the compiler saw it
applied?

Just a naive attempt... Not sure if this matches your use case and
requirements - this will only work for a one-level hierarchy with an
abstract root class and will probably require some ugly gymnastics
inside the Foo method implementations:

abstract class Foo<T extends Foo<T>> {
protected abstract T self();

public T foo1() {
return self();
}
}

class Bar extends Foo<Bar> {
public Bar bar() {
return this;
}

@Override
protected Bar self() {
return this;
}
}

Best regards,
Patrick
 
M

Mike Amling

I'd like to use the "call methods in a chain" pattern
across a class-subhierarchy, with most of the methods
defined in the base-class.

Suppose, I had two classes:

class Foo {
public Foo foo1() {
/* do something very interesting ... */
return this;
}
// assume there were like 100 such foo#() methods here
// (in practice they of course have more diverse names)
}
class Bar extends Foo {
public Bar bar() {
/* do something very interesting */
return this;
}
}

And then, somewhere else:

// the single-class chain works just fine:
new Foo().foo1().foo42().foo84();

// but if I start with a Bar, and eventually after some foo#() calls
// want to call method bar() which is not in Foo, then I'm out of luck:
new Bar().foo1().foo42().foo84().bar(); // doesn't work, of course!

Is there a way to use *generics* for the methods of class Foo such that
each foo#() returns the *static* type on which the compiler saw it
applied?

Alternatives, that do NOT satisfy me:
a) use an explicit cast to (Bar)
((Bar)(new Bar().foo1().foo42().foo84())).bar();
Would turn into a nightmare, when more of Bar's
methods got mixed into the chain.
...
I'm pretty sure, that this would be principally possible (as in: the
compiler has all the information that would be needed),

I don't think the compiler has all the information needed to guarantee
that new Bar().foo1().bar() will be executable at runtime. The compiler
may know, from the "return this" in foo1 that it's safe if you run with
the Foo.class and the Bar.class files that it is now generating. But the
compiler also should know that the Bar.class file it's writing may be
run with a Foo.class file from a later compile of a Foo.java that's been
changed to, say,

public Foo foo1() {
// Wonderful things
return new Foo();
}

Mike Amling
 
T

taqmcg

Alternatives, that do NOT satisfy me:
a) use an explicit cast to (Bar)
((Bar)(new Bar().foo1().foo42().foo84())).bar();
Would turn into a nightmare, when more of Bar's
methods got mixed into the chain.
....
Thanks in advance!
A variant of this approach that might be clearer is to have

class Foo {
....
Bar toBar() {
return (Bar) this; // Throws exception if called inappropriately
}
}

Then you can write a long sequence as:

new Bar().foo1().foo2().toBar().bar3().bar4().foo5().toBar().bar6()...

and simply insert a toBar() whenever you want a foo followed by a bar.
However this would require Foo to know about Bar.

This you might be able to get around that with generics...

class <T> Foo {
...
T toType() {
return (T) this;
}
}

class <T> Bar extends Foo {...}


and then

new Bar<Bar>.foo1().foo2().toType().bar1().bar2().foo3().toType().bar3();

I assumed you have all of your fooN and barN methods defined as
Foo<T> or Bar<T>
in their return type.


Regards,
Tom McGlynn
 
T

taqmcg

A variant of this approach that might be clearer is to have

class Foo {
....
Bar toBar() {
return (Bar) this; // Throws exception if called inappropriately
}
}

Then you can write a long sequence as:
new Bar().foo1().foo2().toBar().bar3().bar4().foo5().toBar().bar6()...

and simply insert a toBar() whenever you want a foo followed by a bar.
However this would require Foo to know about Bar.



This you might be able to get around that with generics...
Or not... I had thought that since generic resolution occurs at compile time the actual type might be used, but that's not the case. So the rest of my suggestions doesn't work. Should have checked <before> writing!

Tom McGlynn
 
R

Robert Klemme

Responding to Andreas Leitgeb:

Just a naive attempt... Not sure if this matches your use case and
requirements - this will only work for a one-level hierarchy with an
abstract root class and will probably require some ugly gymnastics
inside the Foo method implementations:

The approach is all but naive. And it can actually be made to work with
deeper hierarchies in a type safe way. There is only a single
@SuppressWarnings("unchecked") here:

package inh;

public class Foo<T extends Foo<?>> {

public T foo() {
System.out.println(getClass().getName() + " in foo()");
return self();
}

@SuppressWarnings("unchecked")
protected final T self() {
return (T) this;
}

public static void main(String[] args) {
new Baz<Baz<?>>().foo().baz().bar();
new TheEnd().foo().last().baz().bar();
}

}

class Bar<T extends Bar<?>> extends Foo<T> {
public T bar() {
System.out.println(getClass().getName() + " in bar()");
return self();
}

}

class Baz<T extends Baz<?>> extends Bar<T> {
public T baz() {
System.out.println(getClass().getName() + " in baz()");
return self();
}
}

final class TheEnd extends Baz<TheEnd> {
public TheEnd last() {
System.out.println(getClass().getName() + " in last()");
return self();
}
}

A final class does not need a type parameter any more as it does not
need to propagate it.

Kind regards

robert
 
A

Andreas Leitgeb

That's already somewhat better than my "a)" :)
Or not... I had thought that since generic resolution occurs at compile time
the actual type might be used, but that's not the case. So the rest of my
suggestions doesn't work. Should have checked <before> writing!

In my "a)" I already used casts, so doing some unchecked-stuff is
at least not principially worse. I tried doing the generic stuff
directly on "toType()":

class Foo {
Foo foo() { /* ...; */ return this; }

@SuppressWarnings("unchecked")
<T> T toType() { return (T)this; }
}
class Bar extends Foo {
Bar bar() { return this; }
}
...
new Bar().foo().<Bar>toType().bar();

easily beats my original 'a)', but is still a bit awkward to use. ;-)

Thanks for your answer, anyway!
 
A

Andreas Leitgeb

Mike Amling said:
I don't think the compiler has all the information needed to guarantee
that new Bar().foo1().bar() will be executable at runtime.

You're right about the way that I wrote the foo() method: returning Foo.

I hoped, one could spice up method foo() with some specific
generic wizardry, such that the compiler would see a return
type, that (almost) nothing else than "this" could satisfy.

That would prevent even overrides of foo() returning anything else
than their "this" pointer. Alas, there doesn't seem to exist this
kind of wizardry in today's Java.

Thanks, anyway :)
 
A

Arivald

W dniu 2013-11-26 01:50, Andreas Leitgeb pisze:
In my "a)" I already used casts, so doing some unchecked-stuff is
at least not principially worse. I tried doing the generic stuff
directly on "toType()":

class Foo {
Foo foo() { /* ...; */ return this; }

@SuppressWarnings("unchecked")
<T> T toType() { return (T)this; }
}
class Bar extends Foo {
Bar bar() { return this; }
}
...
new Bar().foo().<Bar>toType().bar();

easily beats my original 'a)', but is still a bit awkward to use. ;-)

Maybe this way it looks better to use:

class Foo {
Foo foo() { /* ...; */ return this; }

@SuppressWarnings("unchecked")
<T> T cast(Class<T> c) { return (T)this; }
}

class Bar extends Foo {
Bar bar() { return this; }
}

new Bar().foo().cast(Bar.class).bar();
 
R

Robert Klemme

I hoped, one could spice up method foo() with some specific
generic wizardry, such that the compiler would see a return
type, that (almost) nothing else than "this" could satisfy.

That would prevent even overrides of foo() returning anything else
than their "this" pointer. Alas, there doesn't seem to exist this
kind of wizardry in today's Java.

Why don't you think that my solution [1] qualifies?

Kind regards

robert


[1] Message-ID: <[email protected]>
 
P

Patrick Roemer

Responding to Robert Klemme:
Responding to Andreas Leitgeb:

Just a naive attempt... Not sure if this matches your use case and
requirements - this will only work for a one-level hierarchy with an
abstract root class and will probably require some ugly gymnastics
inside the Foo method implementations:

The approach is all but naive. And it can actually be made to work with
deeper hierarchies in a type safe way. There is only a single
@SuppressWarnings("unchecked") here:

package inh;

public class Foo<T extends Foo<?>> {

public T foo() {
System.out.println(getClass().getName() + " in foo()");
return self();
}

@SuppressWarnings("unchecked")
protected final T self() {
return (T) this;
}

public static void main(String[] args) {
new Baz<Baz<?>>().foo().baz().bar();
new TheEnd().foo().last().baz().bar();
}

}

Very nice. The cast just manifests an implicit assumption, so I think
it's justified here. The wildcards are somewhat disconcerting - but
certainly better than not having a general solution at all. :)

Best regards,
Patrick
 
A

Andreas Leitgeb

Robert Klemme said:
I hoped, one could spice up method foo() with some specific
generic wizardry, such that the compiler would see a return
type, that (almost) nothing else than "this" could satisfy.
That would prevent even overrides of foo() returning anything else
than their "this" pointer. Alas, there doesn't seem to exist this
kind of wizardry in today's Java.
Why don't you think that my solution [1] qualifies?
Kind regards
robert
[1] Message-ID: <[email protected]>

Sorry, for not yet answering. I just need some more time to
digest it.

I haven't forgotten it. I casually glance over your and
Patrick's followups, and then re-mark them as unread, to get
back to it later.

I will followup on it, as soon as I feel able to.

I must admit, that the semantic of Foo<T extends Foo<T>>
still causes a stack-overflow in my head. ;-)

Thanks in advance (until I get it into my head).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top