Anonymous subclassing of Callable<?> for calling super()

Discussion in 'Java' started by Christopher Benson-Manica, Mar 8, 2007.

  1. Recently, it chanced that some code like this was written:

    public class Bar extends Foo {
    // Foo has one constructor, taking a List<String> as an argument
    public Bar(final Object... args) {
    super( new Callable<List<String>> () {
    public List<String> call() {
    final List<String> list = new LinkedList<String>();
    // Transform args into String's and put them in the list
    return list;
    }
    }.call() );
    }
    }

    The motivation is to transform Foo's constructor interface into
    something that is more convenient for Bar's clients. This strikes me
    as grievously hacky, but I also don't see another way to accomplish
    this aside from refactoring, which may not even be possible depending
    on where Foo comes from. Is this a reasonable (or at least accepted)
    idiom for accomplishing this goal, or is there a more elegant
    solution?

    --
    C. Benson Manica | I *should* know what I'm talking about - if I
    cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Mar 8, 2007
    #1
    1. Advertising

  2. Christopher Benson-Manica

    Daniel Pitts Guest

    On Mar 8, 8:47 am, Christopher Benson-Manica
    <> wrote:
    > Recently, it chanced that some code like this was written:
    >
    > public class Bar extends Foo {
    > // Foo has one constructor, taking a List<String> as an argument
    > public Bar(final Object... args) {
    > super( new Callable<List<String>> () {
    > public List<String> call() {
    > final List<String> list = new LinkedList<String>();
    > // Transform args into String's and put them in the list
    > return list;
    > }
    > }.call() );
    > }
    >
    > }
    >
    > The motivation is to transform Foo's constructor interface into
    > something that is more convenient for Bar's clients. This strikes me
    > as grievously hacky, but I also don't see another way to accomplish
    > this aside from refactoring, which may not even be possible depending
    > on where Foo comes from. Is this a reasonable (or at least accepted)
    > idiom for accomplishing this goal, or is there a more elegant
    > solution?
    >
    > --
    > C. Benson Manica | I *should* know what I'm talking about - if I
    > cbmanica(at)gmail.com | don't, I need to know. Flames welcome.


    It seems a bit excessive to create a whole new object, just to call a
    method on it. How about a static method?

    public class Bar extends Foo {
    // Foo has one constructor, taking a List<String> as an argument
    public Bar(final Object... args) {
    super( convert(args) );
    }

    private static List<String> convert(Object...args) {
    final List<String> list = new LinkedList<String>();
    // Transform args into String's and put them in the list
    return list;
    }
    }
     
    Daniel Pitts, Mar 8, 2007
    #2
    1. Advertising

  3. On 08.03.2007 17:47, Christopher Benson-Manica wrote:
    > Recently, it chanced that some code like this was written:
    >
    > public class Bar extends Foo {
    > // Foo has one constructor, taking a List<String> as an argument
    > public Bar(final Object... args) {
    > super( new Callable<List<String>> () {
    > public List<String> call() {
    > final List<String> list = new LinkedList<String>();
    > // Transform args into String's and put them in the list
    > return list;
    > }
    > }.call() );
    > }
    > }
    >
    > The motivation is to transform Foo's constructor interface into
    > something that is more convenient for Bar's clients. This strikes me
    > as grievously hacky, but I also don't see another way to accomplish
    > this aside from refactoring, which may not even be possible depending
    > on where Foo comes from. Is this a reasonable (or at least accepted)
    > idiom for accomplishing this goal, or is there a more elegant
    > solution?


    You do not show Foo but as Daniel said already, basically you are
    invoking Foo(List<String> list). The situation would be different if
    you did not invoked call() and just handed the Callable to Foo's
    constructor. Having said that, yes, use a static method as Daniel
    pointed out already.

    Kind regards

    robert
     
    Robert Klemme, Mar 8, 2007
    #3
  4. Christopher Benson-Manica

    Tom Hawtin Guest

    Daniel Pitts wrote:
    > On Mar 8, 8:47 am, Christopher Benson-Manica
    > <> wrote:
    >>
    >> public class Bar extends Foo {
    >> // Foo has one constructor, taking a List<String> as an argument
    >> public Bar(final Object... args) {
    >> super( new Callable<List<String>> () {
    >> public List<String> call() {
    >> final List<String> list = new LinkedList<String>();

    >
    > It seems a bit excessive to create a whole new object, just to call a
    > method on it. How about a static method?


    Or use a static creation method:

    public class Bar extends Foo {
    public static create(Object... args) {
    List<String> list = new java.util.ArrayList<String>();
    // LinkedList is almost always a bad idea.
    // Use Arrays.asList if you want to be uber efficient.
    ...
    }
    private Bar(List<String> args) {
    super(args);
    }
    ...

    Also Callable is defined to throw Exception.

    Tom Hawtin
     
    Tom Hawtin, Mar 8, 2007
    #4
  5. Christopher Benson-Manica

    Chris Uppal Guest

    Christopher Benson-Manica wrote:

    > Recently, it chanced that some code like this was written:
    >
    > public class Bar extends Foo {
    > // Foo has one constructor, taking a List<String> as an argument
    > public Bar(final Object... args) {
    > super( new Callable<List<String>> () {
    > public List<String> call() {
    > final List<String> list = new LinkedList<String>();
    > // Transform args into String's and put them in the list
    > return list;
    > }
    > }.call() );
    > }
    > }


    God help us -- that's /vile/ !


    > The motivation is to transform Foo's constructor interface into
    > something that is more convenient for Bar's clients. This strikes me
    > as grievously hacky, but I also don't see another way to accomplish
    > this aside from refactoring, which may not even be possible depending
    > on where Foo comes from.


    I'd use a static helper. Or, if that turned out to be impossible, take it as
    a very strong indication that the design was a pile of crap and start again.

    BTW, I question whether that idiom is really legal. Or, if it should turn out
    to be within the letter of the JLS law, whether it /should/ be legal.

    The problem is that it makes use of a reference to the object under
    construction (using it to create the instance of the inner class) before the
    superclass's constructor has been invoked. That is forbidden in every other
    part of the Java design. It is OK, however foolish, to pass around references
    to "this" after the superclass constructor has returned, but before your own
    constructor is complete; but it is /not/ OK to do so before calling the
    superclass constructor.

    In fact I'm somewhat surprised that it passed verification in the JVM -- there
    are strict rules about what you can do with a reference to a allocated-but-not
    fully-initialised object, and until the call to the superclass constructor has
    returned, "this" is in an illegal state.

    -- chris
     
    Chris Uppal, Mar 8, 2007
    #5
  6. Daniel Pitts <> wrote:

    > It seems a bit excessive to create a whole new object, just to call a
    > method on it. How about a static method?


    Sounds good to me, that was the insight I was looking for. Thanks.

    --
    C. Benson Manica | I *should* know what I'm talking about - if I
    cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Mar 8, 2007
    #6
  7. Chris Uppal <-this.org> wrote:

    > God help us -- that's /vile/ !


    Well, I wasn't a big fan either, although I did have to be a bit more
    diplomatic about things :) (Perhaps tellingly, a slight elaboration
    on the code in question also exposed a flaw in IntelliJ's code
    inspection - clearly it's at least uncommonly used enough that the bug
    escaped notice until now!)

    > The problem is that it makes use of a reference to the object under
    > construction (using it to create the instance of the inner class) before the
    > superclass's constructor has been invoked.


    I'm still fuzzy on some of the things that lurk hidden from the eyes
    of the casual programmer - but yes, now that you mention it, it's
    obvious.

    > In fact I'm somewhat surprised that it passed verification in the JVM -- there
    > are strict rules about what you can do with a reference to a allocated-but-not
    > fully-initialised object, and until the call to the superclass constructor has
    > returned, "this" is in an illegal state.


    It seems that the Java compiler is smart enough to determine when
    you've clearly overstepped your bounds - say by accessing a field in
    the subclass before the superclass constructor has been called - and
    when you've merely committed stylistic seppuku.

    --
    C. Benson Manica | I *should* know what I'm talking about - if I
    cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Mar 8, 2007
    #7
  8. Christopher Benson-Manica

    Tom Hawtin Guest

    Chris Uppal wrote:
    >
    > BTW, I question whether that idiom is really legal. Or, if it should turn out
    > to be within the letter of the JLS law, whether it /should/ be legal.


    It's certainly an area where the JLS and javac have been at odds in the
    past. In this case, javac seems to consider the nested class to be in a
    static context. At least that is consistent with the output of javap -c
    on 1.6.0 u1 ea b03 (other builds may do something different).

    Tom Hawtin
     
    Tom Hawtin, Mar 8, 2007
    #8
  9. Christopher Benson-Manica

    Chris Uppal Guest

    Tom Hawtin wrote:

    [me:]
    > > BTW, I question whether that idiom is really legal. Or, if it should
    > > turn out to be within the letter of the JLS law, whether it /should/ be
    > > legal.

    >
    > It's certainly an area where the JLS and javac have been at odds in the
    > past. In this case, javac seems to consider the nested class to be in a
    > static context.


    So it does ! Viler and viler...

    (Though, to be honest, that does slightly reduce my distaste for the original
    trick -- at least the code /is/ static, for all it doesn't look it.)

    -- chris
     
    Chris Uppal, Mar 8, 2007
    #9
  10. Christopher Benson-Manica

    Tom Hawtin Guest

    Chris Uppal wrote:
    >
    > So it does ! Viler and viler...
    >
    > (Though, to be honest, that does slightly reduce my distaste for the original
    > trick -- at least the code /is/ static, for all it doesn't look it.)


    The trick looks reasonable, until you realise it isn't doing quite what
    you expected.

    Anyway, I was looking for this bug in particular:

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6226815

    The example of an anonymous inner class within an inner class
    constructor given in the JLS which isn't supposed to compile, does
    (unless -target 1.4 or earlier is used, apparently).

    Note the bug description says the code is from JLS2 (8.8.5.1) and the
    bug is closed on that basis. However 8.8.7.1 (p245) of JLS3 has the same
    code (the maintenance review has a mark against it, but doesn't appear
    to have changed anything). I guess that bug should be reopened.

    http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#229267
    http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.8.7.1

    If only JDKs had version number 0.1 (or 0.2) lower, nested classes could
    have been a VM-level concept.

    Tom Hawtin
     
    Tom Hawtin, Mar 9, 2007
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,872
    Darryl Pierce
    Feb 24, 2005
  2. Fernando Rodriguez

    Getting the super class via the super() function

    Fernando Rodriguez, Nov 21, 2003, in forum: Python
    Replies:
    2
    Views:
    752
    Bob Willan
    Nov 22, 2003
  3. exhuma.twn
    Replies:
    6
    Views:
    313
    exhuma.twn
    Sep 18, 2007
  4. exiquio
    Replies:
    2
    Views:
    565
    exiquio
    Oct 7, 2008
  5. Ulrich Eckhardt
    Replies:
    6
    Views:
    142
    Peter Otten
    Jul 12, 2013
Loading...

Share This Page