Friday, October 5, 2012

Scala-IO Core: Unmanaged Resources

The main design of Scala-IO is around automatic closing of resources each time a resource is accessed in order to ensure that a programmer cannot unintentionally leave resources open in the face of exceptions or other unexpected situations. However, there are cases where the Scala-IO API is desired but the resource management is undesired. The classic case is of reading or writing to System.in and out. Thus Unmanaged resources exist to satisfy this use-case. 

Since unmanaged resources is a less common use-case there is not a factory object like there is for normal managed Resources.  Instead certain objects can be converted to unmanaged resources using the JavaConverters implicit methods as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// JavaConverters implicit methods are required to create the
// unmanaged resources
scala> import scalax.io.JavaConverters._
import scalax.io.JavaConverters._
 
// now that JavaConverters are in scope we can convert
// System.out to a Output object and use it as any normal
// output object except that the stream will not be closed
// WriteableByteChannels can also be converted
scala> System.out.asUnmanagedOutput.write("Not closing right?")
Not closing right?
 
// See, still not closed
scala> System.out.asUnmanagedOutput.write("Still not closed?")
Still not closed?
 
scala> import java.io._
import java.io._
 
// another demonstration of converting an output stream to a
// unmanaged Output object.  This is frowned upon unless
// unavoidable.
scala> val fout = new FileOutputStream("somefile.txt")
fout: java.io.FileOutputStream = java.io.FileOutputStream@23987721
 
scala> val foutOutput = fout.asUnmanagedOutput
foutOutput: scalax.io.Output = scalax.io.unmanaged.WritableByteChannelResource@36b54a77
 
scala> foutOutput.write("Hello ")
 
scala> foutOutput.write("World!")
 
scala> fout.close
 
// see the output object is broken now because the stream is closed
scala> foutOutput.write("boom")
No Main Exception
---
class java.nio.channels.ClosedChannelException(null)
...
 
// The mirror image is converting an input stream to an Input object
scala> val fin = new FileInputStream("somefile.txt")
fin: java.io.FileInputStream = java.io.FileInputStream@4fcbc4de
 
scala> val chars = fin.asUnmanagedInput.chars
chars: scalax.io.LongTraversable[Char] = LongTraversable(...)
 
// normally a LongTraversable will close the resource
// but this LongTraversable is obtained from a unmanagedInput
// so can be used multiple times without closing the resource
scala> chars.head
res19: Char = H
 
scala> chars.head
res20: Char = e
 
scala> chars.head
res21: Char = l
 
scala> chars.head
res22: Char = l
 
// don't forget to close
scala> fin.close
 
// quick demo of using channels
// the following is a major anti-pattern and is
// here mainly for completeness
scala> val fchannel = new RandomAccessFile("somefile.txt", "rw").getChannel
fchannel: java.nio.channels.FileChannel = sun.nio.ch.FileChannelImpl@1e10cb60
 
scala> val fInput2 = fchannel.asUnmanagedInput
fInput2: scalax.io.Input = scalax.io.unmanaged.ReadableByteChannelResource@679a339e
 
scala> println(fInput2.string)
Hello World!
 
scala> fchannel.isOpen
res13: Boolean = true
 
scala> val fOutput = fchannel.asUnmanagedOutput
fOutput: scalax.io.Output = scalax.io.unmanaged.WritableByteChannelResource@9cc8b91
 
scala> fOutput.write("hi there")
 
scala> println(fInput2.string)
hi thererld!
 
// don't forget to close
scala> fchannel.close

4 comments:

  1. Jesse, are there any (may be rough) plans wrt pulling scalax.io into official scala distribution (i.e. eliminating x in scalax)?

    ReplyDelete
  2. We hope to do exactly that. I keep the x mainly so as to remind that it is not yet part of the official distribution

    ReplyDelete
  3. Great! Thanks for your efforts! Can we dream about inclusion into 2.10?

    ReplyDelete
  4. Thank you for your great work!

    I helped me a lot since I started my relationships with Scala :)

    And it's very hard to find really clear and valuable lessons.

    ReplyDelete