If you want the low-level stuff, just use the java APIs. I'm a big fan of the ARM stuff in scala I/O.
The loaner pattern is 'easy' but we see it used *everywhere* when doing I/O. Backing it in as the default for the *high level* API is genius IMHO. It covers 90% of my I/O use cases. When I need nitty gritty low-level, I usually aim for Netty.
In my opinion, a low-level Netty API with a high level API like what Jesse has covers my I/O situations. The ARM library allows some advanced loaner-pattern like activities, but the ability to compose *behavior* objects in I/O is pretty amazing.
I'm personally a huge fan of Jesse's idea to create processors that when evaluated will run over a program. This kind of programming is far more natural for I/O than any other. In fact, I'd even say that decomposing accessing resources from the processing of data in that resource is a huge win. This is why the Haskell/scalaz community is all about Iteratees. It's the right level of abstraction for some really composable modular I/O. (Note: Netty is basically an OO/mutable implementation of the iteratee pattern).
So, if you want the raw low-level stuff, java is probably your best I/O bet. I'm looking for something easy to use that doesn't put a lot of work (like creating a loaner pattern in every project) on me. I can just do for(line <- Path("foo").lines) doProcessing(line), I think we're winning. If I start having to do crazy things like:
withResource(Path("foo").source) { source =>
for { line <- source.lines } doProcessing(line)
}
we've lost. Also note that managed resources compose, so I can do this:
def diff(file1: Path, file2: Path) = for {
(line1, line2) <- file1.lines zip file2.lines
if line1 != line2
} yield diffLine(line1,line2)
Which is *far* cleaner than the loaner pattern version:
def diff(file1: Path, file2: Path) = withResource(file1.source) { s1 =>
withResource(file2.source) { s2 =>
for {
(line1, line2) <- source.lines zip source.lines
if line1 != line2
} yield diffLine(line1,line2)
}
}
While I agree that the underlying raw access API needs to be there, I think the *default* needs to be the managed-resource API. It's far more powerful and less verbose. The mental shift into it isn't very hard. The only downside to it is it's "not like java's API", which is a good thing.
- Josh
- Josh