|
Re: How Scala Changed My Programming Style
|
Posted: Apr 29, 2009 3:30 PM
|
|
> > Since when has the approach of setting a boolean > variable > > inside a loop been considered terrible style? I'd just > > call it an imperative style. That's how I was taught to > > program in C, and how I continued to program in C++, > and > > how I programmed in Java. I did this for years and > years. > > When looking for something in a collection I'd > initialize > > a boolean variable named found to false, then set it to > > true inside the loop. I wasn't clued into making little > > functions so I could avoid mutable variables like > you've > > shown in your example until I was faced with val versus > > var in Scala. Trying to figure out how to get rid of > vars, > > and puzzling over why I would care to to do that, is > where > > I got the insight into how the functional style could > make > > my code better. > > > > Do many people already try and avoid mutable variables > > like this in Java? > > OK you've got me. I'm really only speaking for myself > here. There's no consensus (that I see) that this is bad > style. But I have specific reasons for why I believe it > to be so and the reasons I've often heard for contrary > usually amounts to what you provide: "That's how I was > taught to program in <language X>" > > What you did here is not the worst case of this but it's a > general problem I see in Java: extraneous variables, > usually boolean flags. It actually makes sense in a some > languages specifically those that do not guarantee all > branches of a method return a value or that variables are > assigned before they are used. > > Generally I see things like this: > > int getFoo(int in)
> {
> int out = 0;
>
> switch (in) {
> case 1:
> out = 10;
> break;
> case 2:
> out = 200;
> break;
> case 3:
> out = 15;
> break;
> }
>
> return out;
> }
> > This is then declared to be "good practice" because you > know what getFoo returns: the value of 'out'. This to me > is a 'turtles all the way down' kind of argument. Knowing > the name of the variable that is returned at the end of > the method is not important. > > Consider the alternative style: > > int getFoo(int in)
> {
> switch (in) {
> case 1:
> return 10;
> case 2:
> return 200;
> case 3:
> return 15;
> }
> }
> > Much simpler and if I ask you what it returns it returns > 10 if in is 1, 200 if in is 2 and 15 if in is 3 and... Did > you catch it? This doesn't return anything if something > other than 1, 2 or 3 is provided. What's really cool > about this in Java is that you don't have to catch that > mistake. It won't compile. So if I'm coding on the tail > end of a bender, I just saved myself some frustration. It > might also make me realize that I don't want to return 0 > for all other cases. I might want to do something else if > a negative number was passed in. > > In fact, I actually sometimes write code like you have > done here, although it's usually out of laziness and flags > are sometimes the right choice. The point I'm trying to > make is that by switching to an unfamiliar paradigm you > are able to lose a lot of baggage that you've accumulated > that may not have anything to do with Java at all. > > I actually completely agree with your overall premise here > but it might seem like you set up a straw-man a bit (which > I don't think was your intention.) > Sorry if I unintentionally strawed you. I just was curious if I had missed the Java community talking about this kind of thing. I need to look at the latest Effective Java again for this, because that's pretty influential on how people code, I'd expect.
It looks to me like you have subconscious functional urges trying to manifest themselves in your Java style. Bill Pyne made a good point about using the variables to look at intermediate values in debuggers. I also like to put intermediate values in variables in complex expressions just to give them a name to kind of explain what I'm calculating, just for code readability. But it also can help when debugging I think.
I also was told by someone at some point, maybe back in my C days, that it is better to just have one return statement in a function or method. But I was also told by others that they liked multiple returns to keep the method less nested. I think I usually leaned towards trying to just have one exit point, but I remember not being sure it was the best way.
Anyway, Java's switch statement is an example of how Java kind of pushes its users towards the imperative style. It is an imperative control construct because it doesn't result in a value. Java's equivalent construct, match, can do the same kind of thing. For example, I could say in Scala:
def getFoo(in: Int): Int = { in match { case 1 => return 10; case 2 => return 200; case 3 => return 15; } }
But match is a functional control construct because it results in a value. The value it results in in the previous example is called "Unit", which is a bit like void. But I could simply make it result in an Int like this:
def getFoo(in: Int) = in match { case 1 => 10 case 2 => 200 case 3 => 15 case _ => -1 }
The case _ at the end is a default case, like default in Java switch statements. Scala's match doesn't fall through, either, so you don't need break, and in fact Scala doesn't even have break. The result of this match expression will either be 10, 200, 15, or -1, and because it is the last expression of the method, that value will be returned. No explicit return is needed. When I look at your examples, I get the feeling you're wanting to do this kind of thing in Java, but that Java doesn't make it as easy as Scala. The other thing you did in your previous post was make a little function, which is something I do a lot more in Scala than I did in Java, because Scala encourages that style with its concise syntax for functions and support for local functions (which are functions declared inside other functions, and only available in that scope).
|
|