Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Anonymous subclassing of Callable<?> for calling super()

Reply
Thread Tools

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

 
 
Christopher Benson-Manica
Guest
Posts: n/a
 
      03-08-2007
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.
 
Reply With Quote
 
 
 
 
Daniel Pitts
Guest
Posts: n/a
 
      03-08-2007
On Mar 8, 8:47 am, Christopher Benson-Manica
<(E-Mail Removed)> 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;
}
}

 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      03-08-2007
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
 
Reply With Quote
 
Tom Hawtin
Guest
Posts: n/a
 
      03-08-2007
Daniel Pitts wrote:
> On Mar 8, 8:47 am, Christopher Benson-Manica
> <(E-Mail Removed)> 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
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      03-08-2007
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


 
Reply With Quote
 
Christopher Benson-Manica
Guest
Posts: n/a
 
      03-08-2007
Daniel Pitts <(E-Mail Removed)> 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.
 
Reply With Quote
 
Christopher Benson-Manica
Guest
Posts: n/a
 
      03-08-2007
Chris Uppal <(E-Mail Removed)-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.
 
Reply With Quote
 
Tom Hawtin
Guest
Posts: n/a
 
      03-08-2007
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
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      03-08-2007
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


 
Reply With Quote
 
Tom Hawtin
Guest
Posts: n/a
 
      03-09-2007
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_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/s...oc.html#229267
http://java.sun.com/docs/books/jls/t...s.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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is this a local anonymous class or a member anonymous class Reporter Java 3 05-12-2007 05:23 AM
XS question, calling anonymous function from C Tassilo v. Parseval Perl Misc 3 04-25-2005 02:22 PM
help with an anonymous array of anonymous hashes noeldamonmiller@gmail.com Perl Misc 1 02-10-2005 01:08 AM
Subclassing from System.Web.UI.Page - Designer Error =?Utf-8?B?Q2h1Y2sgSGFlYmVybGU=?= ASP .Net 1 02-20-2004 05:05 PM
Subclassing UserControl makes the Visual Studio designer does not work S Guiboud ASP .Net 1 07-18-2003 03:55 PM



Advertisments