Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #26597 > unrolled thread
| Started by | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| First post | 2013-11-25 00:55 +0000 |
| Last post | 2013-12-10 11:14 -0800 |
| Articles | 20 on this page of 33 — 12 participants |
Back to article view | Back to comp.lang.java.programmer
can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-25 00:55 +0000
Re: can this be done with generics? Arne Vajhøj <arne@vajhoej.dk> - 2013-11-24 21:11 -0500
Re: can this be done with generics? Saxo <jeti789@web.de> - 2013-11-25 01:43 -0800
Re: can this be done with generics? Saxo <jeti789@web.de> - 2013-11-25 01:47 -0800
Re: can this be done with generics? Arne Vajhøj <arne@vajhoej.dk> - 2013-11-26 21:32 -0500
Re: can this be done with generics? Silvio <silvio@internet.com> - 2013-11-25 11:30 +0100
Re: can this be done with generics? Saxo <jeti789@web.de> - 2013-11-25 02:36 -0800
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-25 10:45 +0000
Re: can this be done with generics? Arne Vajhøj <arne@vajhoej.dk> - 2013-11-26 21:35 -0500
Re: can this be done with generics? Silvio <silvio@internet.com> - 2013-11-27 10:48 +0100
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-27 10:18 +0000
Re: can this be done with generics? Patrick Roemer <sangamon@netcologne.de> - 2013-11-25 12:59 +0100
Re: can this be done with generics? Robert Klemme <shortcutter@googlemail.com> - 2013-11-25 22:31 +0100
Re: can this be done with generics? Patrick Roemer <sangamon@netcologne.de> - 2013-11-26 12:03 +0100
Re: can this be done with generics? v_borchert@despammed.com (Volker Borchert) - 2013-11-26 21:32 +0000
Re: can this be done with generics? Robert Klemme <shortcutter@googlemail.com> - 2013-11-26 23:30 +0100
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-27 18:53 +0000
Re: can this be done with generics? Sebastian <news@seyweiler.dyndns.org> - 2013-11-28 22:28 +0100
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-30 14:21 +0000
Re: can this be done with generics? Mike Amling <mamling@chaff.us> - 2013-11-25 09:02 -0600
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-26 01:04 +0000
Re: can this be done with generics? Robert Klemme <shortcutter@googlemail.com> - 2013-11-26 08:16 +0100
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-26 20:42 +0000
Re: can this be done with generics? Arne Vajhøj <arne@vajhoej.dk> - 2013-11-26 21:38 -0500
Re: can this be done with generics? Mike Amling <mamling@chaff.us> - 2013-11-27 11:05 -0600
Re: can this be done with generics? taqmcg@gmail.com - 2013-11-25 08:36 -0800
Re: can this be done with generics? taqmcg@gmail.com - 2013-11-25 09:04 -0800
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-26 00:50 +0000
Re: can this be done with generics? Arivald <NOSPAMarivald@interia.pl> - 2013-11-26 07:10 +0100
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-11-27 18:58 +0000
Re: can this be done with generics? Daniel Pitts <newsgroup.nospam@virtualinfinity.net> - 2013-12-07 09:04 -0800
Re: can this be done with generics? Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> - 2013-12-07 19:20 +0000
Re: can this be done with generics? Daniel Pitts <newsgroup.nospam@virtualinfinity.net> - 2013-12-10 11:14 -0800
Page 1 of 2 [1] 2 Next page →
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-25 00:55 +0000 |
| Subject | can this be done with generics? |
| Message-ID | <slrnl9580s.42s.avl@gamma.logic.tuwien.ac.at> |
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!
[toc] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2013-11-24 21:11 -0500 |
| Message-ID | <5292b1e5$0$301$14726298@news.sunsite.dk> |
| In reply to | #26597 |
On 11/24/2013 7:55 PM, Andreas Leitgeb wrote:
> 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
[toc] | [prev] | [next] | [standalone]
| From | Saxo <jeti789@web.de> |
|---|---|
| Date | 2013-11-25 01:43 -0800 |
| Message-ID | <0220ee18-c57b-4b6e-b98f-5a2323d99427@googlegroups.com> |
| In reply to | #26598 |
> 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 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 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
[toc] | [prev] | [next] | [standalone]
| From | Saxo <jeti789@web.de> |
|---|---|
| Date | 2013-11-25 01:47 -0800 |
| Message-ID | <ee863bf5-c1ee-49ff-895b-4dca837579f4@googlegroups.com> |
| In reply to | #26600 |
Am Montag, 25. November 2013 10:43:07 UTC+1 schrieb 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 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 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 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.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2013-11-26 21:32 -0500 |
| Message-ID | <529559d8$0$299$14726298@news.sunsite.dk> |
| In reply to | #26600 |
On 11/25/2013 4:43 AM, Saxo wrote: >> 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 > 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 an object of type id and leave things to your > responsability whether things will work well. Sounds similar to C# dynamic. But it is still a dynamic typed language feature in an otherwise static typed language. Arne
[toc] | [prev] | [next] | [standalone]
| From | Silvio <silvio@internet.com> |
|---|---|
| Date | 2013-11-25 11:30 +0100 |
| Message-ID | <529326dc$0$16012$e4fe514c@news2.news.xs4all.nl> |
| In reply to | #26598 |
On 11/25/2013 03:11 AM, Arne Vajhøj wrote:
> On 11/24/2013 7:55 PM, Andreas Leitgeb wrote:
>> 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
>
>
>
>
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.
[toc] | [prev] | [next] | [standalone]
| From | Saxo <jeti789@web.de> |
|---|---|
| Date | 2013-11-25 02:36 -0800 |
| Message-ID | <4542fbbd-ebf9-47c0-8e0c-943c3cbe9fff@googlegroups.com> |
| In reply to | #26603 |
> 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.
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-25 10:45 +0000 |
| Message-ID | <slrnl96aj3.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26603 |
Silvio <silvio@internet.com> wrote: > On 11/25/2013 03:11 AM, Arne Vajhøj wrote: >> On 11/24/2013 7:55 PM, Andreas Leitgeb wrote: >>> 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. :(
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2013-11-26 21:35 -0500 |
| Message-ID | <52955a60$0$299$14726298@news.sunsite.dk> |
| In reply to | #26603 |
On 11/25/2013 5:30 AM, Silvio wrote:
> On 11/25/2013 03:11 AM, Arne Vajhøj wrote:
>> On 11/24/2013 7:55 PM, Andreas Leitgeb wrote:
>>> 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.
>
> 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.
Having a language feature that works in some cases but not in
other cases depending on whether the compiler can see the
constructor or not is not a good design.
Arne
[toc] | [prev] | [next] | [standalone]
| From | Silvio <silvio@internet.com> |
|---|---|
| Date | 2013-11-27 10:48 +0100 |
| Message-ID | <5295bfee$0$15882$e4fe514c@news.xs4all.nl> |
| In reply to | #26632 |
On 11/27/2013 03:35 AM, Arne Vajhøj wrote:
> On 11/25/2013 5:30 AM, Silvio wrote:
>> On 11/25/2013 03:11 AM, Arne Vajhøj wrote:
>>> On 11/24/2013 7:55 PM, Andreas Leitgeb wrote:
>>>> 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.
>>
>> 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.
>
> Having a language feature that works in some cases but not in
> other cases depending on whether the compiler can see the
> constructor or not is not a good design.
>
> Arne
>
Nonsense. The compiler does not need to see the constructor or the
method definition. The method could just as well be in an interface (a
trait in Scala terminology).
The type "this.type" is a singleton type that is unique for each object.
It is simply an explicit construct that says the return value of a
method in a class or interface X is the object itself. Among other
things that means that if it is called on a reference of type Y (where Y
is a subtype of X) the return type is Y and not X.
The construct can be used to achieve what the OP intended. It has a more
important function in Scala though. Scala has path dependent types where
not only the type but also the actual identity returned by a method can
be significant. With path dependent types you sometimes need to narrow
the return type of a method in class X to this.type instead of X to
express that no other instance of X will be returned.
Nothing weird going on here and not very much different from covariant
return in Java where the type of the reference matters as well.
Silvio
For those interested, a tiny example:
class X
{
class Y
def me : X = this
def myself : this.type = this
def createY = new Y
var y : Y = _
}
val x1 = new X
val x2 = new X
x1.y = x1.myself.createY //fine
x2.y = x2.me.createY //type mismatch, expected x2.Y found X#Y
x1.y = x2.y //type mismatch, expected x1.Y found x2.Y
x2.y = x1.createY //type mismatch, expected x2.Y found x1.Y
Here x1.Y is type Y from X instance x1 while X#Y is the less restricted
type of all Ys from any X.
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-27 10:18 +0000 |
| Message-ID | <slrnl9bhng.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26632 |
Arne Vajhøj <arne@vajhoej.dk> wrote: > Having a language feature that works in some cases but not in > other cases depending on whether the compiler can see the > constructor or not is not a good design. Your claim itself is trivially correct, but it has nothing to do with this thread's topic. :-) (The premises are not held - the compiler would have a reliable source for the relevant information.)
[toc] | [prev] | [next] | [standalone]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2013-11-25 12:59 +0100 |
| Message-ID | <l6ve31$4r8$1@newsreader4.netcologne.de> |
| In reply to | #26597 |
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
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2013-11-25 22:31 +0100 |
| Message-ID | <bfhtunF18miU1@mid.individual.net> |
| In reply to | #26608 |
On 25.11.2013 12:59, Patrick Roemer wrote:
> Responding to Andreas Leitgeb:
>> 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:
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
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2013-11-26 12:03 +0100 |
| Message-ID | <l71v6f$mj0$1@newsreader4.netcologne.de> |
| In reply to | #26614 |
Responding to Robert Klemme:
> On 25.11.2013 12:59, Patrick Roemer wrote:
>> Responding to Andreas Leitgeb:
>
>>> 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:
>
> 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
[toc] | [prev] | [next] | [standalone]
| From | v_borchert@despammed.com (Volker Borchert) |
|---|---|
| Date | 2013-11-26 21:32 +0000 |
| Message-ID | <l73420$7kk$2@Gaia.teknon.de> |
| In reply to | #26614 |
Robert Klemme wrote:
> public class Foo<T extends Foo<?>> {
Foo<T extends Foo<T>>
--
"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert <v_borchert@despammed.com>
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2013-11-26 23:30 +0100 |
| Message-ID | <bfklobFis1vU2@mid.individual.net> |
| In reply to | #26628 |
On 26.11.2013 22:32, Volker Borchert wrote:
> Robert Klemme wrote:
>
>> public class Foo<T extends Foo<?>> {
>
> Foo<T extends Foo<T>>
No. That does not work.
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-27 18:53 +0000 |
| Message-ID | <slrnl9cftp.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26614 |
Robert Klemme <shortcutter@googlemail.com> wrote:
> public class Foo<T extends Foo<?>> {
> public T foo() { /* do stuff */ 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() { /* do stuff */ return self(); }
> }
> class Baz<T extends Baz<?>> extends Bar<T> {
> public T baz() { /* do stuff */ return self(); }
> }
Finally I got my head around it.
This is f***ing brilliant && you're genious!
For the extra win, my "source" of objects are really static factory methods,
instead of "new"s, so the code on users' end now essentially looks like this:
getFoo().foo() /* compiler would correctly refuse .bar() or .baz() here */ ;
getBar().foo().bar() /* compiler would correctly refuse .bar() here */ ;
getBaz().foo().bar().baz(); /* all fine */
It can't get any better than that.
(In case it's already too long since I last said it: you're genious!)
Thanks also to Patrick for his draft!
[toc] | [prev] | [next] | [standalone]
| From | Sebastian <news@seyweiler.dyndns.org> |
|---|---|
| Date | 2013-11-28 22:28 +0100 |
| Message-ID | <l78ci7$2s0$1@news.albasani.net> |
| In reply to | #26641 |
Am 27.11.2013 19:53, schrieb Andreas Leitgeb:
> Robert Klemme <shortcutter@googlemail.com> wrote:
>> public class Foo<T extends Foo<?>> {
>> public T foo() { /* do stuff */ 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() { /* do stuff */ return self(); }
>> }
>> class Baz<T extends Baz<?>> extends Bar<T> {
>> public T baz() { /* do stuff */ return self(); }
>> }
>
> Finally I got my head around it.
>
> This is f***ing brilliant && you're genious!
>
> For the extra win, my "source" of objects are really static factory methods,
> instead of "new"s, so the code on users' end now essentially looks like this:
>
> getFoo().foo() /* compiler would correctly refuse .bar() or .baz() here */ ;
> getBar().foo().bar() /* compiler would correctly refuse .bar() here */ ;
> getBaz().foo().bar().baz(); /* all fine */
>
> It can't get any better than that.
>
> (In case it's already too long since I last said it: you're genious!)
>
> Thanks also to Patrick for his draft!
>
I'm late butting in this discussion, but this looks related to the
"getThis() trick", see here:
http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206
That explanation might help in understanding Robert's coding.
-- Sebastian
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-30 14:21 +0000 |
| Message-ID | <slrnl9jt3r.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26653 |
Sebastian <news@seyweiler.dyndns.org> wrote:
> Am 27.11.2013 19:53, schrieb Andreas Leitgeb:
>> Robert Klemme <shortcutter@googlemail.com> wrote:
>>> public class Foo<T extends Foo<?>> {
>>> public T foo() { /* do stuff */ 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() { /* do stuff */ return self(); }
>>> }
>>> class Baz<T extends Baz<?>> extends Bar<T> {
>>> public T baz() { /* do stuff */ return self(); }
>>> }
>
> I'm late butting in this discussion, but this looks related to the
> "getThis() trick", see here:
> http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206
Thanks for the pointer.
Related, yes. Essentially it is what Patrick first suggested.
While Angelika Langer covers the base for nice class hierarchies, where
only leaf-classes are not abstract (and therefore can do without casts),
Robert traded castfree-ness for the ability to do it with hierarchies
involving instanciable non-leaf classes.
The risks of accepting the cast can be summarized in a short example:
new Foo<Bar<?>>().bar(); // compiles fine, throws later.
and I'm fine with taking that risk in my context.
[toc] | [prev] | [next] | [standalone]
| From | Mike Amling <mamling@chaff.us> |
|---|---|
| Date | 2013-11-25 09:02 -0600 |
| Message-ID | <bfh72pFqrh7U1@mid.individual.net> |
| In reply to | #26597 |
On 11/24/13 6:55 PM, Andreas Leitgeb wrote:
> 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
--
Silvio, Silvio grande
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.java.programmer
csiph-web