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 | 13 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 2 of 2 — ← Prev page 1 [2]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-26 01:04 +0000 |
| Message-ID | <slrnl97sst.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26610 |
Mike Amling <mamling@chaff.us> wrote: > On 11/24/13 6:55 PM, Andreas Leitgeb wrote: >> // 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 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. 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 :)
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2013-11-26 08:16 +0100 |
| Message-ID | <bfj074F7hcsU1@mid.individual.net> |
| In reply to | #26617 |
On 26.11.2013 02:04, Andreas Leitgeb wrote: > 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: <bfhtunF18miU1@mid.individual.net> -- 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-26 20:42 +0000 |
| Message-ID | <slrnl9a1td.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26619 |
Robert Klemme <shortcutter@googlemail.com> wrote: > On 26.11.2013 02:04, Andreas Leitgeb wrote: >> 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: <bfhtunF18miU1@mid.individual.net> 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).
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2013-11-26 21:38 -0500 |
| Message-ID | <52955b12$0$299$14726298@news.sunsite.dk> |
| In reply to | #26610 |
On 11/25/2013 10:02 AM, Mike Amling wrote:
> 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
Incompatible changes to a dependency class later does not bother
many other language constructs.
Arne
[toc] | [prev] | [next] | [standalone]
| From | Mike Amling <mamling@chaff.us> |
|---|---|
| Date | 2013-11-27 11:05 -0600 |
| Message-ID | <bfmn2dF128jU1@mid.individual.net> |
| In reply to | #26633 |
On 11/26/13 8:38 PM, Arne Vajhøj wrote: > On 11/25/2013 10:02 AM, Mike Amling wrote: >> >> 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 > > Incompatible changes to a dependency class later does not bother > many other language constructs. Yes, in particular I've noticed the hijinks that the switch (enum instance) bytecode goes through to get runtime compatibility with a separately modified and recompiled enum class. Mike Amling -- If agua is good, then two guas must be better.
[toc] | [prev] | [next] | [standalone]
| From | taqmcg@gmail.com |
|---|---|
| Date | 2013-11-25 08:36 -0800 |
| Message-ID | <64aa69a2-3f7f-452a-96de-572672b229d0@googlegroups.com> |
| In reply to | #26597 |
On Sunday, November 24, 2013 7:55:56 PM UTC-5, Andreas Leitgeb wrote:
>
>
> 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
[toc] | [prev] | [next] | [standalone]
| From | taqmcg@gmail.com |
|---|---|
| Date | 2013-11-25 09:04 -0800 |
| Message-ID | <fae58729-a510-49ac-9bbf-7dd7980adbc8@googlegroups.com> |
| In reply to | #26611 |
On Monday, November 25, 2013 11:36:08 AM UTC-5, taq...@gmail.com wrote:
> On Sunday, November 24, 2013 7:55:56 PM UTC-5, Andreas Leitgeb wrote:
>
> >
>
> >
>
> > 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...
>
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
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-26 00:50 +0000 |
| Message-ID | <slrnl97s39.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26612 |
taqmcg@gmail.com <taqmcg@gmail.com> wrote:
> On Monday, November 25, 2013 11:36:08 AM UTC-5, taq...@gmail.com wrote:
>> On Sunday, November 24, 2013 7:55:56 PM UTC-5, Andreas Leitgeb wrote:
>> > 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()...
That's already somewhat better than my "a)" :-)
>> 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!
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!
[toc] | [prev] | [next] | [standalone]
| From | Arivald <NOSPAMarivald@interia.pl> |
|---|---|
| Date | 2013-11-26 07:10 +0100 |
| Message-ID | <l71e0d$ojk$1@news.dialog.net.pl> |
| In reply to | #26616 |
W dniu 2013-11-26 01:50, Andreas Leitgeb pisze:
> taqmcg@gmail.com <taqmcg@gmail.com> wrote:
>> On Monday, November 25, 2013 11:36:08 AM UTC-5, taq...@gmail.com wrote:
>>> 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!
>
> 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();
--
Arivald
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-11-27 18:58 +0000 |
| Message-ID | <slrnl9cg63.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26618 |
Arivald <NOSPAMarivald@interia.pl> wrote: > W dniu 2013-11-26 01:50, Andreas Leitgeb pisze: >> 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: > new Bar().foo().cast(Bar.class).bar(); Yeah, slightly better, but nothing (within the limitations of current Java) can beat Robert's solution. Thanks, anyway :)
[toc] | [prev] | [next] | [standalone]
| From | Daniel Pitts <newsgroup.nospam@virtualinfinity.net> |
|---|---|
| Date | 2013-12-07 09:04 -0800 |
| Message-ID | <pyIou.381562$5W.329013@fx11.iad> |
| In reply to | #26597 |
On 11/24/13 4: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.
> 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!
>
Yes, this *can* be done with generics, but its relatively ugly and hard
to maintain. I've been doing a lot of work in PHP lately, and they have
a return type hint "@return $this", which makes my IDE of choice
recognize the intent. Java, though superior in many ways, is lacking
that kind of ability.
To answer your question though:
abstract class Foo<T extends Foo<T>> {
public T foo1() { return getThis(); }
protected abstract T getThis();
}
class Bar extends Foo<Bar> {
public Bar bar1() { /* something interesting */ return this; }
protected T getThis() { return this; }
}
It gets uglier if you need multiple levels of inheritance, or if you
have two classes which refer to each other.
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> |
|---|---|
| Date | 2013-12-07 19:20 +0000 |
| Message-ID | <slrnla6t71.42s.avl@gamma.logic.tuwien.ac.at> |
| In reply to | #26769 |
Daniel Pitts <newsgroup.nospam@virtualinfinity.net> wrote: > Yes, this *can* be done with generics, but its relatively ugly and hard > to maintain. Thanks for the answer, but you're a bit late to the party, and both the getThis()-approach as well as a slightly "dirtier"(with unchecked casts) solution that also works with instanciable non-leaf-classes have already been posted. :)
[toc] | [prev] | [next] | [standalone]
| From | Daniel Pitts <newsgroup.nospam@virtualinfinity.net> |
|---|---|
| Date | 2013-12-10 11:14 -0800 |
| Message-ID | <5KJpu.155652$uW4.7754@fx30.iad> |
| In reply to | #26771 |
On 12/7/13 11:20 AM, Andreas Leitgeb wrote: > Daniel Pitts <newsgroup.nospam@virtualinfinity.net> wrote: >> Yes, this *can* be done with generics, but its relatively ugly and hard >> to maintain. > > Thanks for the answer, but you're a bit late to the party, and both the > getThis()-approach as well as a slightly "dirtier"(with unchecked casts) > solution that also works with instanciable non-leaf-classes have already > been posted. :) > Yeah, I saw that after I posted :-) Cheers.
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.java.programmer
csiph-web