Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #26597 > unrolled thread

can this be done with generics?

Started byAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
First post2013-11-25 00:55 +0000
Last post2013-12-10 11:14 -0800
Articles 13 on this page of 33 — 12 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  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]


#26617

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2013-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]


#26619

FromRobert Klemme <shortcutter@googlemail.com>
Date2013-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]


#26625

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2013-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]


#26633

FromArne Vajhøj <arne@vajhoej.dk>
Date2013-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]


#26640

FromMike Amling <mamling@chaff.us>
Date2013-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]


#26611

Fromtaqmcg@gmail.com
Date2013-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]


#26612

Fromtaqmcg@gmail.com
Date2013-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]


#26616

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2013-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]


#26618

FromArivald <NOSPAMarivald@interia.pl>
Date2013-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]


#26642

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2013-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]


#26769

FromDaniel Pitts <newsgroup.nospam@virtualinfinity.net>
Date2013-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]


#26771

FromAndreas Leitgeb <avl@gamma.logic.tuwien.ac.at>
Date2013-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]


#26829

FromDaniel Pitts <newsgroup.nospam@virtualinfinity.net>
Date2013-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