I’ve expanded on the range types a little bit and created an open source project for them. In particular they now support subranges in a typesafe way.
Category Archives: programming
Statically checked range types in Scala
I was showing off some Scala features earlier (specifically “Oh, hey, look. With proper singleton support + implicit arguments you can completely remove the need for a dependency injection container while losing none of the advantages”. More on that later…) and got to discussing the language with Craig, a coworker of mine (well, specifically our CTO. I work at a cool company. :-) ).
He asked me if Scala supported range types, to which my answer was something along the lines of “Well, no. But it should be possible to add as a library. Hmm. Might be hard to get it statically enforced though”.
Turns out it’s not. Here’s some code: http://snippets.dzone.com/posts/show/4876
How do we use this?
scala> import ranges.Range; import ranges.Range scala> val myRange = new Range(0, 10); myRange: ranges.Range = [email protected] scala> val myRange2 = new Range(0, 20); myRange2: ranges.Range = [email protected] scala> val array = new myRange.CheckedArray[String] array: myRange.CheckedArray[String] = [email protected] scala> myRange.indices.foreach(x => array(x) = x.toString) scala> array.mkString res6: String = Index(0)Index(1)Index(2)Index(3)Index(4)Index(5)Index(6)Index(7)Index(8)Index(9) scala> array(myRange.minIndex); res8: String = Index(0) scala> array(myRange.maxIndex); res9: String = Index(9) scala> array(myRange2.minIndex);:8: error: type mismatch; found : myRange2.Index required: myRange.Index val res10 = array(myRange2.minIndex); ^ scala> array(myRange.minIndex.mid(myRange.maxIndex)); res11: String = Index(4) scala> array(myRange.minIndex + myRange.maxIndex); :8: error: type mismatch; found : myRange.Index required: String val res13 = array(myRange.minIndex + myRange.maxIndex); ^ scala> import myRange._; import myRange._ scala> array(myRange.minIndex + myRange.maxIndex); :11: error: type mismatch; found : Int required: myRange.Index val res14 = array(myRange.minIndex + myRange.maxIndex); ^ scala> array(minIndex + maxIndex); :11: error: type mismatch; found : Int required: myRange.Index val res15 = array(minIndex + maxIndex); ^
CheckedArrays (and similarly ArraySlices) are scoped to a particular range object. You can only access them with indices from that same object. You can get Index objects by getting the minimum, the maximum, combining them with various operators, iterating over them or converting from an Integer (at which point it will either min/max it into bounds or throw an IndexOutOfBoundsException if the integer is out of bounds, depending on which method you call).
If you import the range (I’m thinking of separating that out into a separate object for convenience with working with multiple ranges) you’ll get an implicit convertion from indices to integers (*not* the other way around).
Currently nonexistent: Support for subranges, or working with multiple ranges (Update: See below). I think I know how to fix these in a niceish way.
Always going to be nonexistent: Can’t statically verify that two ranges are equal. This isn’t possible in principle, but even simple cases like knowing that new Range(0, 10) and new Range(0, 10) are equal types isn’t doable. I don’t think this is avoidable without special logic in the compiler or significantly more static resolution of objects than Scala is ever likely to have (e.g. I think we could do this using ML functors and sharing constraints, but it’s been so long since I’ve looked at those that I’m not really sure).
Update: Working with multiple ranges is always going to suck without language changes. There’s not enough sharing of values at compile time to express what it needs to. Subranges will probably still work though.
Update 2: It’s been observed that if you don’t know Scala then it’s non-obvious how this code works. Unlike Java, inner classes of different instances in Scala are actually different types. So given
val range1 = new Range(0, 10); val range2 = new Range(0, 10);
range1.Index and range2.Index are different types, and may not be freely converted between. So this code works by having Range enforce that its Index elements are in bounds, and the compiler enforces that you can’t mix Index elements from different ranges.
Minor irritations
I just noticed the following issue in Java. It’s never bothered me before, so it’s clearly not that big a deal, but I find it vaguely annoying.
The following code is not legal:
final Foo foo;
try{
foo = stuff();
} catch (Exception e){
foo = otherStuff();
}
The compiler thinks that foo might already have been assigned in the catch block, even though it clearly can’t have been.
The reason is presumably that it doesn’t distinguish it from the following code:
final Foo foo;
try{
foo = stuff();
bar();
} catch (Exception e){ // Might have been thrown from bar.
foo = otherStuff();
}
Which is reasonable. I’m not sure if I’d really want this edge case to be handled specially.
As Ricky Clarkson pointed out in ##java, what would really be much nicer is:
final Foo foo = try { stuff(); } catch(Exception e) { otherStuff(); }
i.e. Compound expressions ala Scala (or GCC extensions, or any number of other languages). It would avoid a lot of annoying edge cases with assigning to final variables.
This isn’t really a “Please add this to Java 7” request. I don’t care enough and the list of desired features is getting annoying. It’s just a minor irritation with the language.
Don’t forget to fly
I saw this comic a while ago and it occurred to me during today’s HUG.
I think the analogy is obvious, but I’m going to spell it out anyway because I feel the need to rant about it. (As a side note, I know I’ve occasionally been guilty of what I’m ranting about. Hopefully I’ve stopped…)
You like functional programming. That’s great. You write C#/Java/C++/Brainfuck/PL-SQL/Malbolge during your day job. That’s a shame, but oh well. You and everyone else. I bet you really wish you could use folds/lazy evaluation/lightweight threading/COMEFROM statements in your work code. Great. Me too.
There’s a lot of neat stuff in functional programming (and in the better OO languages. And in logic programming. And in a wide variety of other things). So, use it. Go wild. Write code.
DON’T waste time posting endless blog posts about how closures are awesome and wonderful and here’s an example of how they might work in Java. “Here’s a nice bit of code I wrote” is one thing. “Here’s how to implement a for loop. Isn’t it awesome!!!”? Not so much. If you’re interested in something, use it. Don’t waste time thinking about how to shoehorn its features into a language you know far too well.
You can fly. Stop thinking about how great it would be to do so and go out and do it.
Dependency injection in Scala
I (and some others in #scala) have been wondering recently about the state of play for dependency injection in Scala. This is mostly just a brain dump of a few thoughts and a request for feedback. If anyone has any good ideas, please share!
As I see it, most of the Java dependency injection frameworks should work fine for Scala. Guice won’t because of generics issues, and similarly the generics support from other frameworks (e.g. Spring’s type collections) won’t though, so you lose a great deal of type safety. You’re back to an almost Java-like level of type safety in fact. :) Also these don’t take advantage of many of Scala’s great features (higher order functions and a more advanced object system in particular), so the whole thing seems rather unsatisfactory.
I wondered briefly about a system based on abstract method injection using traits, but I couldn’t make it work in a satisfactory manner. The fact that you’d expose dependencies as defs was also unsatisfactory because it means that the compiler doesn’t know that they’re stable so you can’t e.g. import them.
There was some discussion in #scala last night about how “dependency injection is useless if you have higher order functions”. This seems like nonsense to me. A well designed scala program may have less need for DI because of the presence of higher order functions but the basic need for composing of modules (that’s what dependency injection frameworks really are after all – a module composition DSL) is still there, for more or less the same reason why Scala has objects as well as functions.
It’s not entirely clear to me how DI should work in Scala, both from an API and an implementation point of view. Something Guice-like might be a good starting point (but only a starting point! Porting Guice verbatim to Scala would almost certainly be a bad idea), but it’s not clear to me how one would even implement it in Scala. Part of the problem is that Scala lacks a satisfactory metaprogramming facility. It can use Java’s reflection, but the scala.reflect packages seem sadly meager. (There do seem to be a bunch of interesting sounding classes in there, but there appears to be no documentation or evidence of prior usage, so I can’t figure out what on earth they’re for).
