I think Java is particularly bad in this department, since I think it often really encourages with the "Let the IDE handle it for you" mentality.
I think Java is particularly bad in this department, since I think it often really encourages with the "Let the IDE handle it for you" mentality.
I will assert, though I can't demonstrate it, that had this been done in Lisp, the boilerplate problem could have been substantially alleviated by using Lisp macros. One piece of evidence: J2EE has improved this problem substantially by using Java's relatively-new "annotation" feature, which, broadly speaking, has some of the same mojo as Lisp macros, when used properly.
On the other hand, you can do a lot better even in Java. Look at Spring and the other new post-J2EE frameworks. The experience with J2EE has led to learning and improvement in these new "dependency-injection" frameworks, which is definitely a good thing for the Java world.
Lisp Macros are boilerplate without the duplication. (And so without the drawbacks)
When you want to run water to your house, you don't hire someone to design new pipes for you; you use the ones pipe companies kick out. The boilerplate is just plumbing your IDE manufactures for you. The only difference between it and the magic that happens in dynamic languages with stuff like RoR is that boilerplate code is explicit rather than implicit. I prefer the former, truthfully, so I don't have to understand the whole stack to work on a small piece of the code.
* What the valid arguments are
* What will be returned
* What, if any side effects calling the function will cause
* (sometimes) What resources the function will utilize
Use of most other data types is simpler. Your framework or library should give you this information in the documentation. If your development environment is reasonably friendly, it will give you the arguments, and in many cases, you'll be able to guess the rest of it based on the function name.
If you have to RTFS to figure out how to use your libraries, something is wrong. Institutionalizing that by always putting the source right in front of you is a Bad Thing.
To make this concrete, take the example of implementing getters for a class in Python. If my class has four fields
class GetterDone:
a = 1
b = 2
c = 3
d = 4
I can do something like this inside the class to implement getters: def get_a(self):
return self.a
def get_b(self):
return self.b
def get_c(self):
return self.c
def get_d(self):
return self.d
Or I can do something like this: def __getattr__(self, attr):
if attr.startswith("get_"):
return lambda: getattr(self, attr[4:])
raise AttributeError
The latter does a good job of eliminating boilerplate, but at the cost of making it near impossible for me to find out how get_a() is implemented (assuming this was buried in a huge codebase). class GetterDone
attr_reader :a, :b, :c, :d
end
Rather than being a runtime attr.startswith check, this will generate actual "return self.foo" methods in the class.Think of this as generating code using a UI, except you record the minimal UI commands, rather than putting the full output into your source files. The commands themselves are still explicit, it's just that they contain only the interesting information with the minimum amount of boilerplate.
There are methods to create read-write and (I think? write-only) properties as well.
Just play along and imagine a more complex world. If it makes you happier, pretend the getter is intended to return the string version of the numbers or some other operation that would make just using instance.a wrong.
A simple example of this is generating getters/setters. Autogenerating the code works great 99% percent of the time. The problem comes in for that 1% case where a non-templated getter or setter is needed. That special case is easy to lose track of in the forest of automatically generated code. Groovy solves this problem by automatically generating all of the getters/setters for you, but if you need to you can still override the automatic definition with a specific implementation.
I won't argue you with that too much magic can be a bad thing. However, for the code I typically generate with my IDE I really think I'm wasting time and bloating my code.