A Simple REPL (Read, Evaluate, Print Loop) in Swift

Posted on Sun 03 June 2018 in Swift

We looked in the last post at how to get arguments from the command line. We will also be interested in how to build a REPL---a Read, Evaluate, Print Loop that reads input from the keyboard and responds until some exit condition is met, and then exits. program is often called a REPL—a Read, Evaluate, Print Loop. This fundamentally requires us to be able to read lines from the keyboard and process them.

Here's some Swift that does that (based on information in this post).

// readline.swift  [Swift 4.1; Xcode 9.3.1; 2018-05-27]
//
// Implement a trivial REPL.
//

print("Type something: ", terminator: "")
while let line = readLine() {
    print("(Just to show I got it) you typed '\(line)'")
    print("Type something: ", terminator: "")
}
print("\nBye!")

Points to note:

  • The print statement includes the extra (named) argument terminator, which specifies what should be added to the string we give. By default, this is a newline (\n), but here we want Type something: to act as a prompt, so we don't want a trailing newline. By specifying the empty string terminator, we avoid this.
  • The while condition {statements} construct will be fairly familiar to anyone who's ever seen a C-style language, but the condition may look slightly unfamiliar.
    • First, no parantheses are require around the condition, as they would be in C and friends.
    • readLine() is a function call that returns what Swift calls an optional String, which is to say, it either returns a string (whatever the user types) or a null value (nil), if the user terminates the input with the end-of-file character (^D on Unix and Linux; ^Z on Windows, though I don't know how relevant that is in a Swift context).
    • let assigns a name (in this case line) to a constant value, i.e. one that cannot be changed after assignment.
    • So the construction while let line = readLine() is a condition that will be satisfied whenever the value is non-null even if the input is empty.
    • As a strongly, statically-typed language, Swift usually requires nulls to be handled in one of a few well-defined ways, including protecting against them as shown. We'll see other ways in the future.
  • The only notable thing in the body of the while loop is the use of '\(line)' in the string to be printed. Strings can include arbitrary expressions by using \(...) syntax. In this case, we are just grabbing the value of the variable. The result of such expressions (perhaps surprisingly) does not have to be String: whatever is produced will be cast to a string.
  • In total, then, this program simply repeatedly asks the user for input, and echoes it back, until input is terminated, either by breaking out (e.g. with ^C), or by ending input with the ^D end-of-file character.

Here's what happens if we compile it and interact with it:

$ ./readline
Type something: Hello
(Just to show I got it) you typed 'Hello'
Type something:
(Just to show I got it) you typed ''
Type something: (That was just a carriage return)
(Just to show I got it) you typed '(That was just a carriage return)'
Type something: Next up will be end-of-file
(Just to show I got it) you typed 'Next up will be end-of-file'
Type something: ^D
Bye!
$