Re: Embedded DSLs and Productivity
Posted: Apr 11, 2006 3:48 PM
> If all the getters and setters do it get and set, why do
> you need them at all? They are equivalent to public
I think I see what you're getting at. You're right about get/set being equivalent to a public instance variable, except that get/set does provide a layer of abstraction that allows you in the future to change their implementation without breaking clients. Admitedly that doesn't happen very often. In our case, though, the getters are type checked, but the setters are often private and used only by Hibernate via reflection. Some of our setters are public, because they are mutable fields. So in that case, it is really just info hiding and conforming to the standard way of doing attributes in Java.
> interface Reflection
> java beans basically treat Objects like Maps.
I see. You're saying that although with this interface you're not getting static type checking, if your are accessing the bean attributes via reflection, you aren't getting static type checking with that approach either. In my entity case, we were using reflection for most set methods, but all the clients were explicitly calling the get method, which was statically checked. And by having private set methods, we get info hiding. In the generic JavaBeans case, I think there are a lot of non-reflective use of beans, in which case the get/set approach would be preferred (in my opinion) because it is more explicit and more type safe. So you get type safe direct access, and you also have the possibility to use reflection.
> > - It finds type errors at compile time, sooner rather
> > than later.
> How many errors do this help you find? I can count the
> number over 6 months on one hand these errors are not the
> ones that keep me late at work.
Do you use an IDE? Do you ever select from a list of methods to call that make sense for the type of the variable? Do you get a little red squiggle sometimes that you then fix? All those are fancy ways of preventing or fixing compile-time type errors. That happens to me all the time. One of the things I really like about these modern IDEs is that I get fewer compiler errors of any kind, because as I go I'm notified of just about anything that won't compile.
I also get type errors occasionally that the compiler doesn't find. For example, if I have a method that takes three Strings in a row, sometimes I might get them out of order. That happens now and then too, and since it isn't checked at compile time, I find out at runtime (or unit test time).
I think the more useful way to ask this question is how many errors does static type checking help you find that you don't find via unit testing, or quickly via plain old testing, using a non-static language such as Python, Ruby, or Smalltalk. I find that static type checking catches all kinds of problems, but the question is, is it worth the added programmer pain compared to dynamic alternatives? My feeling about that is that the answer depends on the situation. For our build automation, for example, I think the answer is that static types is not worth the pain. For our web application, I think it is.
> > - It gives my IDE more information that it can use to help
> > me refactor more quickly and safely, lookup lists of
> > methods to call after a dot, etc...
> This I agree with. But you can get this without the type
> checks. All you need is the type.
I agree. It isn't the checking that I'm talking about in general, although that's what I kept referring to in my previous post, it is the specification of types in the program that I'm talking about. In other words, my point is not type checking so much as about specifying the types in the program. This is what Dave Thomas seems to consider a poor design choice for a language, and I was trying to challenge that view.
> It's really a subtle
> difference but by making casting implicit, it would make a
> lot of code more clear.
> The question is whether you allow calling an arbitrary
> method on an Object of unknown type. I'm not sure that's
> a good choice for Java.
What do you mean by making casting implicit?
> > - At runtime it gives the optimizer more information to
> > work with, which can help it do a better job of
> > optimizing.
> Again, this is accomplished by types, not static type
Agreed. Another one is that a static analyzer has more information to work if the variables have types. I expect FindBugs to help me a bit more than pychecker (though I have little experience with either). I just expect that the more information the analysis tool has at its disposal, the more useful the analysis can be.
> This (dependency checking) is the true value.
Especially as the program grows in size.
> ...As I work with dynamic tools, I see that the code
> gets done just as well, it's just that later it's very
> hard to figure out what it's doing or how it can be
> changed without breaking things. Java code also gets done
> just more slowly but is (usually) easier to transform in
> place. For this reason, I am experimenting with Jython
> and Java in unison. Java for the 'hard' core components
> and Jython for the more trivial and less reusable pieces.
> This 'good cop, bad cop' approach has a lot of promise in
> n our work.
This is something I've wanted to do too, use Java to build the API bricks that I then script against with a less verbose language. But I've never been able to let go of the refactoring support I get from my IDE when I stick with Java everywhere. How have you handled that? In other words, if you say script your controllers in Jython, and maybe your tests, and you go to do some major refactors of the Java part, don't you have to change all that Jython stuff by hand? The refactoring browser is one of those analyzers that can do more useful things because the type information is there. In the Jython portion, even if the IDE supported refactoring, I don't see how it can do as good a job.
What I've taken to doing instead is create DSLs. Our little DSLs are very concise, but the generate the verbose Java code that has strong types. So in cases where I can justify a DSL, I get what I want. Trouble is I force us to write things many times over by hand before creating a DSL to make sure we know how to abstract. In the long term, I think we'll be quite fast because of our DSL-code-generators, but in the short term, I'm pretty much going at a typical Java pace.