Then I turned to a new topic: the option type. It solves a certain problem that comes up in programming. Consider the problem of reading data from a file. Generally there is data to read, but what about when you reach the end of the file? What should be returned in that case? I asked people if they knew what happens when you call the Scanner class' method nextLine when end of file is true. Someone pointed out that it throws an exception. I asked if people knew what the built-in System.in variable returns when you call its read method. Nobody seemed to know. I said that the read method returns a value of type int. When you reach end of file, the method returns -1 as a way to say, "There is no more legal input to read." There is another reading class in the Java class libraries known as BufferedReader that has a readLine method. It returns null when you attempt to read beyond the end of a file.
None of these approaches is particularly elegant. What we want is the ability to return different things in different cases. If reading succeeds, we return a value. If it fails, we return a value that would correspond to "nothing". This is what the option type is used for in ML.
As Ullman explains in chapter 4, the TextIO structure has a function called openIn that can be used to open a text file. Once you do that, you can use the function readLine to read individual lines. The return type of readLine is a "string option". That means that sometimes it returns a string, sometimes it doesn't. The two constructors that are used for the option type are NONE and SOME. In fact, you can ask about these in the ML interpreter:
- NONE; val it = NONE : 'a option - SOME; val it = fn : 'a -> 'a optionThe constructor NONE is like our color constants. It doesn't have a value associated with it. But the SOME constructor takes a value of type 'a and returns a 'a option. Here are some examples:
- SOME 3; val it = SOME 3 : int option - SOME "hello"; val it = SOME "hello" : string option - SOME 45.8; val it = SOME 45.8 : real optionIt takes a while for people to get used to the option type because languages like Java don't have anything that is like it. To extract a value from an option, you can call the function valOf. So you might say:
- val x = SOME 82; val x = SOME 82 : int option - valOf(x); val it = 82 : intWe often don't need the valOf function because we instead use pattern matching to define a function that operates on an option, as in:
datatype 'a option = NONE | SOME of 'a;