Prev: Java work from home. Remote (telecommuting) jobs in Java.
Next: Zip question: Where are all the extra characters coming fromupon unzipping?
From: Eric Sosman on 19 Oct 2009 11:08 Andreas Leitgeb wrote: > [...] > I still see some merit in being able to enforce that any concrete > class implementing some thusly declared interface had to offer some > particular c'tor, as a means to help developers of such classes to > not forget about it. That doesn't strike me as a great idea, because it constrains the subclass' implementation rather than its interface. It may be tempting to view a class' constructors as "sort of methods" and as such part of the interface, but I don't think it holds up. Here's my objection: Suppose there's an Entertainer interface (or abstract class) and I'm writing concrete implementations of it. I write Actor and Singer, but when I come to Comedian I realize that every Comedian must have a Joke he can fall back on when the act is dying: A Comedian without a shop-worn stale Joke is no Comedian at all. So to ensure that all Comedians are viable, I give the class a Joke member and initialize it in the constructor: class Comedian implements Entertainer { private final Joke jokeOfLastResort; Comedian(Joke joke) { if (joke == null) throw new IllegalArgumentException("not funny"); jokeOfLastResort = joke; } ... } But suppose that Entertainer (somehow) requires all implementing classes to provide a no-arguments constructor -- maybe even a public no-arguments constructor. How will a Comedian instantiated with that constructor acquire his jokeOfLastResort? We can't let it be null (a Comedian with no Joke would be a Politician), so we're forced to invent some kind of default Joke the no-arguments constructor can use: class Comedian implements Entertainer { ... as above ... private static final Joke DEFAULT = new Joke("Plato and a platypus walk into a bar..."); public Comedian() { this(DEFAULT); } ... } Okay, it might make sense for the class of Comedians to have a default stale Joke (a faithful model of reality, perhaps), but note that the need for something like DEFAULT was *forced* upon us by the requirement for a no-arguments constructor. The author of Entertainer, who knew nothing about the wants and needs of those who would come later, decreed that every implementing class would have usable default values for everything that might ordinarily be passed as arguments to a constructor. Is that much coercive power a good thing to put in the hands of the Entertainer author? I guess one could always evade the requirement: class Comedian implements Entertainer { ... public Comedian() { throw new UnsupportedOperationException( "Please don't use this constructor"); } ... } .... but one would then have to wonder about the utility of Expression's requirement that the constructor exist. -- Eric.Sosman(a)sun.com
From: Arved Sandstrom on 19 Oct 2009 11:32 Marcin Rzeźnicki wrote: > On 19 Paź, 16:13, Andreas Leitgeb <a...(a)gamma.logic.tuwien.ac.at> > wrote: > >> I still see some merit in being able to enforce that any concrete >> class implementing some thusly declared interface had to offer some >> particular c'tor, as a means to help developers of such classes to >> not forget about it. > > Yep, this is not bad. I prefer the annotations-based method such as described here: http://www.javaspecialists.eu/archive/Issue167.html It works very cleanly - my annotations processors are in a separate JAR that I include on the javac classpath. Strictly speaking there's no need to specify the processor path if doing this; it will default to the user classpath if no processor path is specified. The only change I need to make to my "real" source is the actual annotations, like @NoArgsConstructor in the example, and quite frankly on the implementation classes is where I personally want to enforce a condition like this. Because of the @Inherited annotation on the @NoArgsConstructor annotation it becomes particularly handy. I have found use of this approach when a large number of JPA @Entity classes inherit from a @MappedSuperclass - it's not uncommon to want to supply some entities with useful ctors (and if doing so carelessly the no-args ctor goes away); using this kind of annotation on the @MappedSuperclass catches all these problems at compile time. AHS
From: Marcin Rzeźnicki on 19 Oct 2009 11:36 On 19 Paź, 17:32, Arved Sandstrom <dces...(a)hotmail.com> wrote: > Marcin Rzeźnicki wrote: > > On 19 Paź, 16:13, Andreas Leitgeb <a...(a)gamma.logic.tuwien.ac.at> > > wrote: > > >> I still see some merit in being able to enforce that any concrete > >> class implementing some thusly declared interface had to offer some > >> particular c'tor, as a means to help developers of such classes to > >> not forget about it. > > > Yep, this is not bad. > > I prefer the annotations-based method such as described here:http://www.javaspecialists.eu/archive/Issue167.html Nice, it wins :-)
From: Andreas Leitgeb on 19 Oct 2009 11:55 Eric Sosman <Eric.Sosman(a)sun.com> wrote: > Andreas Leitgeb wrote: >> I still see some merit in being able to enforce that any concrete >> class implementing some thusly declared interface had to offer some >> particular c'tor, as a means to help developers of such classes to >> not forget about it. > Here's my objection: Suppose there's an Entertainer interface > (or abstract class) and ... > ... > Okay, it might make sense for the class of Comedians to have a > default stale Joke (a faithful model of reality, perhaps), ... :-) > ... > The author of Entertainer, who knew nothing about the wants and needs > of those who would come later, ... Thanks for the entertaining example, but I think it's beside the point. This type of argument "it's bad for this exemplary usecase, so it must be bad for all usecases" is obviously flawed. (or was a joke, itself) On second thought: If the Entertainers were designed to be dynamically loaded by name, then Comedians just wouldn't have any chance of a individual default joke. They could offer their Joke- constructor, but unless they also offered a no-args one, they just wouldn't ever be successfully engaged. This whole topic is inspired by dynamic loading of classes. Otherwise, there wouldn't really be any use for dictating constructors at all. Dynamic loading of classes seems to me of increasing importance with all those AppServers, J2EE, ... Demanding the default-constructor (or even with a specific set of arguments) for those classes imposes no new restriction, just formalizes the restrictions that were already imposed by documentation and use. PS: In recent threads I spoke up against restrictions, and now I promote them? It's different types of restrictions, of course: an extra method or c'tor is easily added as a dummy, but an idly added "final" is much harder to come by, if deemed improper, later.
From: Andreas Leitgeb on 19 Oct 2009 12:15
Marcin Rzeźnicki <marcin.rzeznicki(a)gmail.com> wrote: > On 19 Paź, 17:32, Arved Sandstrom <dces...(a)hotmail.com> wrote: >> Marcin Rzeźnicki wrote: >> > On 19 Paź, 16:13, Andreas Leitgeb <a...(a)gamma.logic.tuwien.ac.at> >> > wrote: >> >> I still see some merit in being able to enforce that any concrete >> >> class implementing some thusly declared interface had to offer some >> >> particular c'tor, as a means to help developers of such classes to >> >> not forget about it. >> > Yep, this is not bad. >> I prefer the annotations-based method such as described here: >> http://www.javaspecialists.eu/archive/Issue167.html > Nice, it wins :-) Indeed nice, but what would be the extra effort to create e.g. a @StringArgConstructor annotation and its processing? And then also a @StringStringArgConstructor and a @StringMyFooIntArgConstructor, ... As long as this annotation, its processor, and a mechanism to create annotations for any particular constructor-signature aren't yet in the standard, I wouldn't deem them a full substitute... But then again, they do not depend on my deeming it anything... :-) |