A current project has an interface consisting of about two dozen getters (and setters). This interface is implemented by a minimum of two classes due to design and lack of multiple inheritance.
Being forced to implement this functionality in even one place, not tucked away in some base class, module, mixin, etc. is irritating enough: having it in two places is more than twice as bad. Keeping the implementations in sync is irritating. Looking at the code so I know I can ignore it is irritating. Maintaining three sets of code (the interface and two classes) is irritating.
This functionality is available for Java--sort of. Warth et al. created Expanders via the Polyglot compiler front end. It allows classes to be non-invasively updated with new methods, fields, and superinterfaces.
Expanders look like what we want, and like the rest of Java, are statically-typed, preventing at least some types of errors.
package some.pkg; public class SomeJavaClass { // Normal class definition. } ... package interfaces; public expander Foo of SomeJavaClass { private String _someProp; public void setSomeProp(final String someProp_) { _someProp = someProp_; } public String getSomeProp() { return _someProp; } } ... import some.pkg; use interfaces.Foo; public class UseThatShiznit { public static void main(final String[] args) { SomeJavaClass anInstance = new SomeJavaClass(); anInstance.setSomeProperty("No brainer."); } }
This is a crude use of Expanders. Consider the creation of a Swing
JTree
-aware class via Expanders: rather than include Swing-specific information in the class itself we can create an Expander that implements TreeNode
and ILabelProvider
and since Expanders are typed, we can create different expanders for different classes. If there is shared behaviors, no worries; Expander behavior can be overridden just like class behavior.use StringIconExp; public expander PublicationExp of Publication implements TreeNode, ILabelProvider { // Enumeration children()... // String getText()... public Icon getIcon() { return "/icons/publication.gif".getIcon(); } }
What's that
getIcon()
code doing?! Strings don't have a getIcon()
method... but strings with an expander do.public expander StringIconExp of String { private Icon icon = null; public Icon getIcon() { if (icon == null) icon = new ImageIcon(Object.class.getResource(this)); return icon; } }
Yes, this could be implemented with source generation tools, but that's a poor substitute for type-safe, naturally-composable functionality in the language itself, and it adds a layer of build-time complexity that must be documented and maintained.
If you think Groovy, Scala, and so on are tough sells, try selling Expanders. It's tantalizing, but experimental, and with the current crop of JVM languages, I doubt we'll be seeing it in mainline Java.
No comments:
Post a Comment