Using a cout << like function with Swift to work with console and String

topGraphic
If you have worked with C++, you might be well aware of the cout function, it is one of the most commonly used functions with C++. That is simply because you can just use it so

//
cout << "Hello World"

and it prints Hello World to the console. Well, using the println(“Hello World”) is not difficult either, but…
There are times when you might not want to have the brackets and you could also modify the cout function to print only while in Debug mode or output the data to a website or a file or whatever you want. This might not be possible with the Swift println alone.

This is experimental and does not replicate the complex ways that cout works.

Limitations

This does not chain for now, chaining means that you can use something like

// cout chaining example
//
cout << "Hello Swift " << 1.2 << " from iOS " << 8.4

Right, so let’s dig in and write some code in Playgrounds

Get Started

First we need to have a function called cout this function takes a parameter of type String! and then prints it to the console.

//cout function to handle a string parameter
//
func cout(theParam:AnyObject!){
  println("\(theParam)")
}

The next thing we need to do is to override the << operator to be of type infix . There are three types of operators (look for another tutorial coming soon on them), simply put, the one that is used before an expression is of type prefix as in !found , the one that is at the end is a postfix as in factor! and the one that is in between two expressions is an infix as in value != 4000 . Note the operators can be any of the approved ones, here for consistency I have used the ! is all three examples.

// function for the << operator
//
infix operator << {}  // Have to set this once

func << (leftSide:(AnyObject!)->(), rightSide:AnyObject!) {
  leftSide(rightSide)
}

to illustrate that infix has two parameters, the leftSide and the rightSide . Where we expect the leftSide to be a function and a parameter of type AnyObject! . When this is called, it simply in turn invokes the function that is passed with the parameter. It is if you may want to call it, syntactic sugar to call the function passed.

With these two functions in place, you can simply start using this as

// using the << functions

cout << "Hello from Learn Swift"
cout << 3.14
cout << 8
cout << true
cout << nil
cout << "That's all folks."

Since we are passing it a function you can also call it with other functions that have a similar signature.
one that you can start using straight away is println , replace the cout in the above functions with println and they work.

// using the << functions

println << "Hello from Learn Swift"
println << 3.14
println << 8
println << true
println << nil
println << "That's all folks."

Trouble in Paradise

This all works fine till you try to use variables instead of literals. If you were trying to print the value of a variable, it would not work and the compiler would complain. There is a reason for that, while it may seem that String, Int, Bool , etc are all types and should be covered under the AnyObject , it is not the case. The reason is simple and can stump quite a few developers, because AnyObject is an Object where as String, Int, Float, Bool etc are struct s.
To make them work, you will have to have another function that handles the parameter of that type.

//
func << (theFunc:(AnyObject!)->(), theParam:String) {
  theFunc(theParam)
}

Now this code would work fine

//
var theString = "Hello from the string"
cout << theString

Similarly, you will have to create one for each type that you want to support. Since this code is for testing purposes, I have not tried to make a generic function that would work eliminating the need for adding additional functions (if even possible).

Adding data to strings

The last bit of this cout function for the scope of this article is to add data to a string. In C++, you can use cout to not only output to the console, but also to output to strings.
To accomplish that you need to add another version of the << function, one that takes a String as a parameter instead of the function.

//
func << (inout theFunc:String, theParam:AnyObject){
  theFunc = "\(theFunc)\(theParam)"
}

There is another thing to note, the keyword inout . This indicates that the parameter can be altered. You can set the value of this variable from within the function. Generally parameters passed to a swift function cannot be altered.

//
var theString  = "Hello "
theString << "Jayant"
cout << theString

How cool is that? Some exercise for you to try, you can add more variations of the functions to include other types, like

//
func << (theFunc:(AnyObject!)->(), theParam:Int){
    theFunc(theParam)
}

and now you can handle variables of type Int .

Closing thoughts

Chaining is going to be a little more involved than anticipated because Swift would complain that

you cannot have non-associative operators adjacent to other operators of the same precedence

.
What this means in simple terms is that you cannot have something like a == b == c.

Secondly, while you can assign functions to a variable, there are some variables (generics, I presume) that cannot be assigned to variables as easily so you can create a generic wrapper to include those. For example

//
func cout<T> (t:T) {
  println(t)
}

instead of using let cout = println which would not work as expected
Source: gottesmm on IRC

Views All Time
Views All Time
3393
Views Today
Views Today
1
Posted in Basics, Tutorial and tagged , , , , , , , .

One Comment

Comments are closed.