Chaining cout in swift like C++

In an earlier article, we discussed the possibility of adding a cout like functionality in Swift as seen in C++ (http://swift.oz-apps.com/2015/04/using-a-cout/). There were a couple of impediments that prevented the full functionality of our cout function. Let us revisit that and add chaining

What is Chaining?

Chaining in simple terms is running several commands as if they were all part of the same. For example you could (on the command line use) cat myfile.txt | grep "swift" | wc -l .

These are three commands and if you ran them separately, they would work differently. The cat myfile.txt would display the contents of myfile.txt.
grep "swift"would search for the word swift, but would require an input so by itself you would pass it the filename you want to search the text in, or use the input from the console.
Lastly wc -l would count the number of lines.

However when you pipe them (the correct terminology in Unix) it would run the first command and pass the output of that command as the input to the second and then the output of the second would be used as the input of the third, and so on. It works on a simple fact that the input is the standard output of the previous command.

Why was cout created?

C had printf and it worked fine, you could use printf to format values like so

and it would not work in a type safe environment as the function is expecting a string but is being passed a number. You can read in detail on this issue and the reason why cout was created (it is beyond the scope of this article).

In context of this article and Swift, this cout function was created to provide the cout like feature to Swift developers. Secondly it also allows for slightly better readability and usage specially while working with direct values is a bit cumbersome and difficult (as you would see in the more usage scenarios below).

Chaining Cout

Back to our task at hand, chaining cout. Let us look at the code we had from last time, we declared a function called cout and we declared an operator override for <<. However when we wanted to use something like cout << "Xcode" << 6.3we could not as it complained something about

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

We can fix that one easily in the function declaration with

Function error

This would have worked, but there is a small problem. Our function is declared as

which means it expects the first parameter to be a function and the second parameter could be AnyObject. So when we try something like cout << "Xcode" << 6.3 it balks because cout is a function BUT “Xcode” is not, it is a String.

the code cout << "Xcode " << 6.3 is treated by the << function as

where as what it should be is

Fixing the function to chain

This is perhaps one of the easiest ways but often overlooked method in coding. My experience / exposure to this was from the days of Visual Basic, where you could simply use something like

This allowed you to access the properties and methods in the with block. Without that block the context was set to the main form. Then there was some discussion on using this on a couple of forums in the past year where the idea was to chain commands in a similar fashion where you could use something like (pseudo-code follows)

This could only be possible IF each of the functions returned the same object, because in essence this code is the equivalent of

we employ a similar technique with the function << and we return the same function back. Our new declaration for the << function would look like

and now if we try to chain cout << "Xcode" << 6.3it will work

Using Variables not Magic Numbers

Using magic numbers is not very useful, what if you had a variable called version that you wanted to use for cout? If you try that with the function

it will not work and Swift being Swift, will provide you with the most helpful compiler error that will instantly let you with pin-point accuracy spot the error. NOT!!
While the error message is not very helpful, we can see that it is because the function is expecting a value of AnyObject. if we used var version:AnyObject = 6.3.the code would work. So the issue is that String or Int is not AnyObject.

One way would be to typecast them, but that is not a good way to deal with this issue, the other better way would be to use generics. So we can further redefine this function as

Now, we can pass it practically any type of values.

Note: It does have issues with structs so while UIColor will work, UIRect will fail.

The Code

The code is simple and would need the two function declarations and would look something like

More Usage scenarios

The first thing we need to do is replace the println in the cout function to a print . This way we can have formatted text in one line than each component on a new line.

Here are some examples of how cout is used in the C++ world.

and you can compare that to the println formatting options which might look smaller but might not offer as much flexibility and readability.

in other related options, if you had to pass strings, it gets a bit weird in swift as you cannot have quotes inside of quotes and have to declare variables.

Note: that the second one will not work as you cannot have quotes inside of quotes. However the same with cout would look like

I am sure that you can see the value, if not that’s ok then this is not for you and don’t use it.

Repository

This code would be added to the Github repository and thereby you can see as it would have any changes. The Github repository can be found at http://github.com/JayantVarma/Swift-cout and maybe even add a playground with an explanation.

Update: The playground is an amazing feature and has some wicked formatting functionality, however it is also unstable and crashes, is slow, buggy and needs restarting more often. It doesn’t matter if the playground was a OS X or an iPhone playground. So, maybe till it is fixed by Apple or is more stable, Playground might not be an alternative option for formatted text and code.

Next time

Now that we can chain, the next step would be to provide this functionality with standard input/output/error streams, files and variables. So keep a look out for this.

Views All Time
Views All Time
788
Views Today
Views Today
1
Posted in Tip, Tutorial and tagged , , , , , .