Using cerr and cout in Swift 3.0

Last year, there was a post called using cout like functionality in Swift which you can find https://swift.oz-apps.com/2015/05/chaining-cout-in-swift-like-c/. There were a lot of changes in Swift and that made that code redundant, so here is a fresh look at the same again

Here’s what we will achieve

cout << "Hello, " << "world" << "\n" << "Eat pie on 14th of march, " << 3.14 << "\n"

Apart from cout , we shall also create the cerr and later we will try to see what we can do for cin.

How do these work?

These are all stream functions like stderr and stdout . The good news is that Swift has a protocol that you can use, it is called TextOutputStream . This has a function called write that takes a string and appends it to the stream.

first, we define our structure that conforms to the TextOutputStream object.

public struct StdOutputStream: TextOutputStream {
    var stream: UnsafeMutablePointer<FILE>

    init(_ forStream: UnsafeMutablePointer<FILE>) {
        stream = forStream
    }
    
    public mutating func write(_ string: String) {
        fputs(string, stream)
    }
}

Using the init function we can use the same structure to create objects for both the streams by simply passing to them the swift objects stderr and stdout which are of type UnsafeMutablePointer<FILE>

var errStream = StdOutputStream(stderr)
var outStream = StdOutputStream(stdout)

Note: We made them mutable using a var instead of a let because we want to keep appending the text to the stream

Creating the functions

We need two functions cout and cerr , these will take a parameter of Any and returns nothing.

func cout(_ val: Any) -> Void {
    print(val, terminator:"", to: &outStream)
}

func cerr(_ val: Any) -> Void {
    print(val, terminator:"", to: &errStream)
}

Using Operators Overload

We need the operator << to tie all of this together to create what we are after. This also works in playgrounds and should work on a linux system (will update after I try that out). When we use an operator more than once in an equation, we need to indicate the precedence. In the prior version, we set the associativity to indicate how the calculations are. In this case we need the associativity of left . With Swift 3, we have to set up precedencegroup which contains the associativity .

Another thing, to save ourselves creating a signature every time, we can create a typealias instead.

typealias closure = (Any) -> Void
precedencegroup test { associativity: left }
infix operator << : test
func << (l:@escaping closure, r:Any) -> closure {
    l(r)
    return l
}

Now we are ready to use our function and operator,

cout << "Hello, " << "world" << "\n" << "Eat pie on 14th of march, " << 3.14 << "\n"

What else can it handle?

This is a stream that handles a string, so we can add more things like enums, arrays, etc including system structures like Rects and Frames. In cases of objects, it can display details like you see in the debug console window. If you create objects that have CustomDebugStringConvertible you can display the information to the streams.

Views All Time
Views All Time
1072
Views Today
Views Today
1
Posted in Uncategorized.