Programming Style Guide: Command Query Separation

An important aspect of programming, and one that people don’t think of to often, is being able to express the intentions of the code clearly.

Most of the times we programmers get lost in the code we write. It is important to step back and take a look at the code we have written from another person’s perspective. One can say, “But that’s what documentation is supposed to do right? Provide information to others!”. Yes, but that’s not the only way. A good example of that is a situation we often face with functions.

Command Query Separation

Most functions can be generalised into 2 categories.

Command Functions

Functions that act on instructions sent to it and make changes to the underlying data/model. These are commands given to a function and the callee is not expecting a response.

Query Functions

Functions that are used as queries to examine the underlying data/model. The callee is most certainly expecting a response. The function should not modify the underlying model in any way.

It is not common to find a function that does both. In fact, to be consistent command functions must never return a response and a query function must only return a response. This is how ideal separation happens. This way programmers can easily distinguish between Commands & Queries and the objective of the function becomes clear.

The real world however is quite different. Most functions we write are not guaranteed to work the way we want. The likelyhood of an error occurring while a function is being run is very high. This can happen during data validation or some underlying process. Hence, most functions are very likely to return a response indicating the success of a function. This is done using a variety of techniques. It is this feature that throws Command Query Separation for a toss.

In this article we are going to look at some ways in which we can achieve Command Query Separation while still retaining error handling capabilities.

Let us start by looking at the example written below.

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: Value of type double. The result of the division is returned. If the denominator is 0 the function returns 0
*/
double division(const double &firstNumber, const double &secondNumber)
{
     if (!floating_point_equality(firstNumber, secondNumber))
     {
          return firstNumber / secondNumber;
     }
     return 0.0;
}

The function is a rather simple implementation of division written in C++. It is meant to be a Query function. It immediately becomes clear that we are trying to do 2 things here:

  • We are trying to perform a division
  • We are trying to check if the division succeeded with the help of a return value

The problem is the fact that the function returns error codes and the result the same way. Any programmer using this function will have to write the code to distinguish between the two.

In this case the error is represented by the value ‘0’. There is no way for the caller to tell if the result of the division was 0 or if there was an error. It gets even worse if the function is a pure command function. A pure command function ideally should not return anything. However we will have to return a value to account for errors.

Here is an example of a Command Function:

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: An error code in the form of an integer. A '0' indicates success. '-1' indicates division by Zero error.
*/
int display_division_of_numbers(const double &firstNumber, const double &secondNumber)
{
     if (!floating_point_equality(secondNumber, ZERO))
     {
          std::cout&lt;&lt;firstNumber&lt;&lt;&quot; divided by &quot;&lt;&lt;secondNumber&lt;&lt;&quot; = &quot;&lt;&lt;(firstNumber / secondNumber)&lt;<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>&lt;std::endl;
          return 0;
     }
     else
     {
          return -1;
     }
}

As we can see the function is a command function. It shouldn't be returning a value. But we are forced to return a value to communicate success.

Let us look at some alternatives.

Returning Error Codes

This approach is the one that was implemented above & has the obvious short comings.

Passing An Error Code variable

This is the next best approach. Instead of returning an error code pass in an object that represents error. After the call is completed, check to see if the error object is nil/NULL. This ensures that the return value always corresponds to an answer and nothing else.

//Potential Error Codes

typedef enum ErrorCodes
{
DIVIDE_BY_ZERO, NaN, NEGATIVE_NUMBER
} ErrorCodes;

//ErrorCode struct. This is the object that contains error information
typedef struct ErrorCode
{
public:
     ErrorCode(const ErrorCodes &code, const std::string &description)
     :errCode(code), errDescription(description)
     {

     }

     std::string description() const
     {
          return errDescription;
     }

private:
     //Holds the code
     ErrorCodes errCode;

     //holds additional information
     std::string errDescription;
} ErrorCode;

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Argument 3: Holds a pointer to the error code object. If the object is nil then there was no error.
Returns: Value of type double. The result of the division is returned.
*/

double division_of_numbers(const double &firstNumber, const double &secondNumber, ErrorCode **error)
{
     if (!floating_point_equality(secondNumber, ZERO))
     {
          return firstNumber / secondNumber;
     }
     else
     {
          *error = new ErrorCode(DIVIDE_BY_ZERO, "Attempting to divide by zero");
     }
     return 0.0;
}

As is obvious from the code above, the return value always corresponds to the answer of the computation. All we have to do is check the ErrorCode pointer to see if it is NULL.

Here is the implementation for the Command Function.

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Argument 3: Holds a pointer to the error code object. If the object is nil then there was no error.
*/
void display_division_of_numbers(const double &firstNumber, const double &secondNumber, ErrorCode **err = NULL)
{
if (!floating_point_equality(secondNumber, ZERO))
{
std::cout<<firstNumber<<" divided by "<<secondNumber<<" = "<<(firstNumber / secondNumber)<<std::endl;
}
else
{
*err = new ErrorCode(DIVIDE_BY_ZERO, "Attempting to divide by Zero.");
}
}

As you can see the function looks like a true Command Function. There is no value being returned. However, the caller still has to check if the Error object is NULL.

Another implementation of this is to use a complex response.

//Potential Error Codes
typedef enum ErrorCodes
{
     DIVIDE_BY_ZERO, NaN, NEGATIVE_NUMBER, NO_ERROR
} ErrorCodes;

//Response struct. It will hold either the error or a response.
typedef struct Response
{
public:
     Response(ErrorCodes err)
     : errCode(err), value(0.0)
     {

     }

     Response(double answer)
     : errCode(NO_ERROR), value(answer)
     {

     }

     ErrorCodes getError() const
     {
          return errCode;
     }

     double getValue() const
     {
          if (NO_ERROR == errCode)
          {
               return value;
          }
          return 0.0;
     }

private:
     ErrorCodes errCode;
     double value;
} Response;

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: A struct of type Response that either contains the value or the error. The caller must examine the struct before probing the value.
*/
Response* division_of_numbers(const double &firstNumber, const double &secondNumber)
{
     if (!floating_point_equality(secondNumber, ZERO))
     {
          Response *answer = new Response(firstNumber/secondNumber);
          return answer;
     }
     else
     {
          Response *error = new Response(DIVIDE_BY_ZERO);
          return error;
     }
}

This approach is a combination of the first 2 approaches. It immediately sends information to the caller that he/she must examine the object for errors before probing for the value. In the earlier example, there is no guarantee that the caller will examine the error. There is no guarantee with this approach either. But at least it simplifies the implementation for the caller and provides an easier mechanism to handle errors without having to manually create error objects.

Something similar is achieved in Swift using Associated Enums.


//Response Enum. It will hold either the error or a response.

enum Response
{
     case Error(String)
     case Value(Double)
}

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: An Enum Response that either contains the value or the error. The caller must examine the struct before probing the value.
*/

func division_of_numbers(firstNumber : Double, by secondNumber : Double) -> Response
{
     if (!floating_point_equality(firstNumber : secondNumber, Equals: ZERO))
     {
          let answer : Response = Response.Value(firstNumber/secondNumber)
          return answer;
     }
     else
     {
          let error : Response = Response.Error("Dividing by Zero")
          return error;
     }
}

Of course the Swift implementation does not need a struct as enums allow us to encapsulate a value in them.

Exceptions & Exception Handling

This is a much better approach. The idea is that you write you function to work as it is normally supposed to. If something goes wrong throw an exception. This approach completely eliminates the need to examine the return value or check to see if there are errors in the response object.

In exception based programming, your code will follow the correct path if there is no problem. If an issue occurs then your code jumps to the part where the error needs to be handled.

Here is an example:

#ifndef MathException_hpp
#define MathException_hpp

#include
#include
#include 

namespace MathematicalExceptions {
     class MathException : public std::exception
     {
          public:
               virtual const char * what() const throw ();
               MathException(const std::string &information);

          private:
               std::string description;
     };
}
#endif /* MathException_hpp */

The next file:

#include "MathException.hpp"

const char * MathematicalExceptions::MathException::what() const throw ()
{
     return description.c_str();
}

MathematicalExceptions::MathException::MathException(const std::string &information)
: description(information)
{

}

the next file.

#include <span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
#include
#include "MathException.hpp"

const double ZERO = 0.0;

//Floating point equality checker
/*
Argument 1: Holds the LHS value of type double
Argument 2: Holds the RHS value of type double
Returns: Boolean value
*/
bool floating_point_equality(const double &amp;firstNumber, const double &amp;secondNumber)
{
     return fabs(firstNumber - secondNumber) &lt; std::numeric_limits::epsilon();
}

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: A struct of type Response that contains the value.
This function throws an exception of type MathematicalExceptions::MathException
*/
double division_of_numbers(const double &amp;firstNumber, const double &amp;secondNumber)
{
     if (!floating_point_equality(secondNumber, ZERO))
     {
          double answer = firstNumber / secondNumber;
          return answer;
     }
     else
     {
          MathematicalExpections::MathException exception = MathematicalExceptions::MathException(&quot;Attempting to divide by zero&quot;);
          throw exception;
     }
}

int main(int argc, const char * argv[]) {
     double numerator = 32.1;
     double denominator = 0.0;
     double answer = 0.0;

     try
     {
          answer = division_of_numbers(numerator, denominator);
     }
     catch (MathematicalExceptions::MathException &amp;err)
     {
          std::cout&lt;&lt;err.what()&lt;&lt;std::endl;
     }
     return 0;
}

Exceptions are about the closest we can come to achieving Command Query Separation. Anyone using functions that implement the Exception throwing and handling capability is clear as to whether it is a Command function or a query function without compromising on safety and error handling in any way.

Here is an example with Swift.

//Exception Enum. Will be used to throw an exception for mathematical operations
enum MathExceptions : Error
{
     case Divide_by_Zero(String)
     case NaN(String)
     case NegativeNumber(String)
}

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
Returns: The value of type Double. The caller must handle any exceptions that might be thrown.
*/
func division_of_numbers(firstNumber : Double, by secondNumber : Double) throws -> Double
{
     if (!floating_point_equality(firstNumber : secondNumber, Equals: ZERO))
     {
          let answer : Double = firstNumber / secondNumber
          return answer;
     }
     else
     {
          throw MathExceptions.Divide_by_Zero("Attempting to Divide by zero.")
     }
}

let ans : Double = 0.0

do
{
     ans = try division_of_numbers(firstNumber: 22.3, by: 0.0)
}
catch let err
{
     print(err.localizedDescription)
}

Again, the Swift implementation is rather Straightforward thanks to Associated Enums which conform to the Error protocol.

Here is how the Command function would look with exceptions.

//Division function
/*
Argument 1: Holds the numerator of type double
Argument 2: Holds the denominator of type double
*/
void display_division_of_numbers(const double &amp;firstNumber, const double &amp;secondNumber)
{
     if (!floating_point_equality(secondNumber, ZERO))
     {
          std::cout&lt;&lt;firstNumber&lt;&lt;&quot; divided by &quot;&lt;&lt;secondNumber&lt;&lt;&quot; = &quot;&lt;&lt;(firstNumber / secondNumber)&lt;<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;">&#65279;</span>&lt;std::endl;
     }
     else
     {
          MathematicalExceptions::MathException exception = MathematicalExpections::MathException(&quot;Attempting to divide by zero&quot;);
          throw exception;
     }
}

This produces a much better implementation of the function, while maintaining the error handling capabilities.

Conclusion

As we can see implementing perfect Command Query Separation is not easy. But by writing our functions properly and by using better error handling such as exceptions it becomes a lot easier to achieve that. Programmers should be able to look at a function & tell if it is a ‘Command’ or a ‘Query’ knowing that error handling is not part of the function signature in any way.

Programming Style Guide: Documentation

Now we will shift our attention to that part of programming which is often ignored. Documentation.

Documentation is a key part of programming. In fact, some might go as far as saying that Documentation is the most important aspect of Programming. Let us understand what we mean by documentation by looking at some key points. Later we will look at different ways of documenting our code.

We document our code so that:

  1. Anyone who is reading our code can understand what we are trying to achieve.
  2. Anyone who wishes to make changes to our code knows where to make the changes.
  3. Anyone who issuing our code can easily find out its capabilities and limitations.
  4. Other programmers can figure out how to use our code.
  5. Developers can find out when and where changes were made to a code. This is useful to understand the evolution of our code.
  6. We can easily recollect what, why, when, where & how something was done by us. This is necessary if we are revisiting code that we have written a long time back.
  7. We can add warnings and disclaimers

There may be some other reasons why we may want to document our code, but the list above summaries the most common reasons. This can easily be seen from a simple example.

func fahr_to_cent(Centigrade temp : Float) -&amp;gt; Float
{
return (32 + (temp * 1.8))
}

It is clear to use what the function does simply from its name. However, there is a lot more information that we can provide. Let us modify the implementation a little bit to make it more informative and readable.

/**
This function takes temperature in Centigrade and converts it to Fahrenheit.
- important: This function does not do data validation
- parameter temp: This is the temperature in Centigrade. It can be a negative value too.
- returns: This is the temperature in Fahrenheit.
- requires: `temp > -273.0 && temp < 1000.0`
- Note: The requirement mentioned is not enforced.
- Since: iOS 11
- author: Arun Patwardhan
- copyright: Copyright (c) Amaranthine 2015
- version: 1.0
*/
func convert_to_fahrenheit_from(Centigrade temp : Float) -&amp;gt; Float
{
     return ((temp * 9.0 / 5.0) + 32.0)
}

The code above looks a lot better now. We made the function name better, but more importantly we have added documentation that better describes the function. This includes range of permitted values, version number, important notes. The comments haven’t been written randomly. They have been formatted in a way that will make them appear in quick help. So now if we have to use the function we know what to watch out for.

Now that we know why we need to document our code let us look at some of the ways this can be done.

Comments

The most common form of documentation is by using comments. Most programming languages support comments. Comments are text which is ignored by the compiler. As such they are not used to build the actual software. The sole reason why they exist is because there has to be some mechanism to write notes.

Single Line Comments

// This is a comment

A single line comment as the name says is a piece of text that can fit in one line.

Good when a short description is required. Normally this is placed before or after a variable as most variables would need a short description.

You can have multiple lines using the Single comment mechanism too.

// This is a comment
// This is a comment on the next line

Multi Line Comments

There is a better way to implement multi line comments. We can enclose the text in a /* */ range.

/* This is a comment
   This is a comment on the next line
   Useful when we have to write really large pieces of comments&amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;gt;&amp;amp;amp;lt;/span&amp;amp;amp;gt;
*/

Use Case

Here are some examples of when comments can or should be used.

/*
        File Name.   : main.cpp
        Date Created : 13th February 2017
        Created By   : Arun Patwardhan
        Project Name : String Parser
        File Contents:
                - Command Line Option selector
                - Different entry points for the remaining code
        Contact      : arun@amaranthine.co.in
*/

This is a classic example of a multi line comment. This comment provides useful information about the name of the file, when it was created, who created it, contact information, the code that is found in this file.

/*
    Exception Possibilities while Reading/Writing from/to Database
    write_error : This is thrown when there is duplicate data that is being
                  written into the database.
    db_empty.   : This is thrown when you attempt to read from an empty data
                  base.
                  Use the func is_empty() method.
    invalid_data: This is thrown when the data to be written is not valid.
    data_missing: This is thrown when insufficient data is passed. If the write
                  operation requires mandatory data an exception is thrown
                  instead of writing default values.
*/
enum DBExceptions : Error
{
    case write_error(String)
    case db_empty(String)
    case invalid_data(String)
    case data_missing(String)
}

This example shows the necessary documentation while declaring a new type. In short its purpose and situations when different values might be used.

Here is an example of code for functions.

@interface Converter : NSObject
/*!
    @brief This is a temperature conversion function

    @discussion This functions takes floating point values and does a floating point conversion to make sure that we get a precise conversion.

    @param temperature This is the value in centigrade that is passed in. Note, negative values can also be passed in. Values whose results exceed the range supported by float will produce un predictable results.

    @return float Returns a floating point value
*/
-(float) convert_to_fahrenheit_from_centigrade:(float) temperature;
@end

The comment gives information about different aspects of the function. Including the rage of values supported. Note that it also uses special markup to allow for the code description to show up in the Help menu bar or when you option click the method.

Comments

This is how the comments with markup look like. They appear in the ⌥ click menu as well as the help menu on the right hand side.

Read Me Files

Another thing one can do along with comments is to create Read Me files. Read Me files are plain text files that are bundled as a part of the project. Unlike comments which give information about a specific piece of code or an entire file, Read Me files give information about the entire project as a whole. Since they are text files we actually treat them as text.

Here is some typical information that is found in a Read Me file:


Project Name : String Parser
Project Request/Ticket Code: 13788
Orignal Project Author : Arun Patwardhan
Contact Details :
– arun@amaranthine.co.in
http://www.amaranthine.in

Platforms on which Application Can Run
– macOS 10.10 or later
– Windows 7 or later
– Linux (Ubuntu 14 or later)

Compiler Supported – g++

Building the Application

make

Testing

strParser -f Test1 -o myOutput1
strParser -f Test2 -o myOutput2

Files
– makefile
This is the file used to build the Application.

– main.cpp
This is the entry point file. The selection of execution path on the basis of command line options is done here.

– Parser.h
This file contains the declaration for the Parser class as well as its internal structure.

– Parser.cpp
This file contains the implementation of the Parser class

– DataStructure.h
This file contains the declaration of the internal structure of the data structure.

– DataStructure.cpp
This file contains the implementation of the internal structure of the data structure.

– Validator.h
This file contains the declaration of the internal structure of the data structure.

– Validator.cpp
This file contains the implementation of the internal structure of the data structure.

– Test1
Runs a basic set of strings as input.

– Output1
Expected output after running Test1. Compare your results with the results of this file.

Libraries Required – Standard Template Library


The above is just a sample Read Me file. In real world implementations these can get a lot bigger with references to links and future developments. Some of the other things that can be mentioned are:

  • Future additions
  • Bugs fixed (potentially with the bug fix request ticket)
  • Limitations
  • Tools that are required to make this code
  • Additional tools that need to be installed
  • Project Status

Naming Conventions

Documentation becomes a lot easier if we follow good naming conventions. Variables, functions, types, files… which are well named in itself become self explanatory and at the very least reduce the amount of documentation required.

Additional Tools Documentation in C++, Objective-C

Doxygen

HeaderDocretired You may come across some projects that use this.

Additional References for Documentation for Swift

Here is an article on Markups for Swift.

 

Adding formatted text to Swift in Xcode

Formatting in Playgrounds and Xcode projects is achieved using Markups in comments. The following article describes some of the things that you can do. Note that there are many more ways of acheiving some of the effects shown here.

The idea behind markups is to make your code more readable whether you are using Playgrounds or Xcode.

If you can only see the commented code in playgrounds and not the rendered markup then click on Editor > Show Rendered Markup to view the rendering. You can use this option to toggle back and forth.

Formatting in Playgrounds

Plain Text

There are different kinds of text you can place in a Playground. Let us look at the code below to see what all is achieved.

//: # Documentation
//: ## Contents
//: * Text Description
//: * Documentation for Functions
//: * Documentation for Types
//: * Formatting Text
//:  - Code
//:  - Italics
//:  - Bold
//: * Inserting Items
//: * Links
//: * Assets
//: * Callouts

The comments here are in the format //:.

Rendered Output

This is how the rendered output looks.

Line 1 shows how to render a Title Text. This is achieved using the # before the text.
Line 2 shows how to get a lower sized text by using ## instead of #. We can achieve more levels if we wish.

For multi line text with bullets use the *, +, – symbols. This is seen on lines 7-13.

It is also possible to create numbered lists too. Simply type the numbered list & it renders accordingly.

//: * Inserting Items
//: 1. Links
//: 2. Assets
//: 3. Callouts

This renders as:

Screen Shot 2017-11-08 at 11.25.27 AM

Playground Pages

It is possible to have multiple pages in Playgrounds. This way we can create a more readable experience that makes the code structured, compartmentalised and easier to understand.

To do that open a playground and then simply add a playground by clicking File > New > Playground Page.

To move from one page to the next simply write the comment.

//: [Next Topic](@next)

This will automatically place a link to jump to the next page.

Similarly you can add a link to move to the previous page.

//: [Previous](@previous)

Code block

We can even show a code block in the text. It is formatted in a different manner to tell the user that it is a code block.

//: ### Code block
/*:
Loop to print characters
````
for char in "Arun Patwardhan"
{
    print(char)
}
*/

This is how it appears:

Screen Shot 2017-11-08 at 11.30.45 AM

Function Help

There is also some formatting that can be done for functions, types and other pieces of code written in a playground. This also appears on the quick help of the sidebar.

We will look at how to create formatted markup for playgrounds.

/*:
## This function takes temperature in Centigrade and converts it to Fahrenheit.
- important: This function does not do data validation
*/
/*:
- Note: "Please refer to Quick Help for more information."
*/
/*:
- Callout(Custom Callout): This is how you create a custom callout ` - Callout(Custom Callout):`
*/
/*:
- Example: `convert_to_fahrenheit_from(Centigrade: 32.0)`
*/

This renders as:

Formatted Markup for Functions

Formatted Markup for Functions.

We will look at formatting the comments to appear in Quick Help in the Formatting for Xcode section.

Inserting Links

The last bit is related to inserting links. We have already seen how to insert links for moving between Playground pages.

Redirecting to URL

/*:
For more articles on Programming, see [Programming articles @ arunpatwardhan.com](https://arunpatwardhan.com/category/programming/)
*/

This renders as:

Screen Shot 2017-11-09 at 11.14.24 AM

Formatting for Xcode

Function Help

As we saw in the earlier section we can create a lot of documentation for Functions. The approach is similar to the one we used in Playgrounds. We will be using callouts to provide information. We will use some callouts for Playgrounds, however, there are many more callouts available for Xcode Symbol Documentation as compared to Playground. The main difference here is the fact that the comments begin with /** instead of /*:.

“The code shown below will work in both, regular Xcode projects as well as Playgrounds.”

/**
This function takes temperature in Centigrade and converts it to Fahrenheit.
- important: This function does not do data validation
- parameter temp: This is the temperature in Centigrade. It can be a negative value too.
- returns: This is the temperature in Fahrenheit.
- requires: `temp > -273.0 && temp < 1000.0` - Note: The requirement mentioned is not enforced. - Since: iOS 11 - author: Arun Patwardhan - copyright: Copyright (c) Amaranthine 2015 - version: 1.0 */
func convert_to_fahrenheit_from(Centigrade temp : Float) -> Float
{
    return ((temp * 9.0 / 5.0) + 32.0)
}

This renders as:

Formatted Markup for Playgrounds as well as Quick Help

Formatted Markup for Playgrounds as well as Quick Help

Note that the quick help appears in the Right hand side sidebar. That too only after you select the function.

As we can see this makes the function a lot more readable. The real advantage of Quick Help comes in the fact that the documentation is now easily accessible no matter which file we are in within the project. The also helps the developer put in the right kind of information, required for proper usage of the function, in the help section.

Note that the rendered markup for Playgrounds will only appear in Playgrounds. 

Inserting Links

Just like in the previous section where we introduced links we can add links to the symbol documentation.

/**
   For more articles on Programming [Programming articles @ arunpatwardhan.com (https://arunpatwardhan.com/category/programming/)
*/
func recursiveFunction(count : inout Int)
{
   while 0 <= count
   {
      count -= 1
      recursiveFunction(count: &count)
   }
}

This renders in Quick Help as:

Screen Shot 2017-11-09 at 11.26.53 AM

Callouts supported by Playgrounds

  • Custom Callout
  • Example

Callouts supported by Symbol Documentation

  • Attention
  • Author
  • Authors
  • Bug
  • Complexity
  • Copyright
  • Date
  • Invariant
  • Precondition
  • Postcondition
  • Remark
  • Requires
  • See Also
  • Since
  • Version
  • Warning

Callouts supported by both Playgrounds & Symbol Documentation

  • Experiment
  • Important
  • Note

When to use Swift & when to use Objective-C?

Over the past few years I have received a number of questions with regards to Swift & Objective-C. Specifically related to the future of the 2. I will try to address those questions in the form of an FAQ.

Should I learn Swift or Objective-C?

This is a question that I get from developers new to iOS/macOS App Development. Ideally speaking, you should learn Swift. As that is going to become the main language for App development on Apple’s ecosystem. However, the reality is a little different. There are a large number of applications that are written in Objective-C. You are likely to encounter them at your workplace. You may also have to maintain, upgrade & improve those apps. In such a case, it makes sense to learn Objective-C too.

Can I mix Swift & Objective-C in the same project?

Yes! But remember that you should check for feature compatibility between the 2 languages. Adding Swift code to an Objective-C project may not be very beneficial as only those features that are compatible with Objective-C can be written in Swift.

Going the other way round is not a problem. You can read more about that here:Mixing Swift & Objective-C

Will Objective-C be deprecated in the future?

That is an interesting question. There is no formal announcement from Apple stating the Objective-C is going to be deprecated. However, one can expect more attention to be paid to Swift. That is where most of the newest techniques, tools & technologies are going to be available. Objective-C will keep running as it is as of now.

Can I mix Swift with other Programming Languages?

Swift can easily be mixed with Objective-C. If you wish to incorporate C++ or C code in your Swift Project then wrapping them in Objective-C code allows you to achieve this.

Apart from that Swift does support working with C code code. You can read about that here:Interacting with C APIs.

Swift does not provide interoperability support for any other languages as of now.

Which version of Swift should I use?

It is recommended that you use the latest available version of Swift. However, the actual version that you work on depends on many other factors like: compatibility with OS Versions, support & business related choices.

Why shouldn’t we just convert all our Objective-C code to Swift and keep things simple?

A very tempting proposition. However, practical realities prevent us from doing this. The process of converting from Objective-C to Swift is time consuming. Apart from having to convert the syntax, the code also needs to be optimised taking into account the new features that are available. This will mean extensive testing and quality assurance. Most companies will not invest their resources into this endeavour.

A better approach is to migrate to Swift gradually. Here are some ways to do this:

  1. If its a brand new product/app that you are creating, start it in Swift.
  2. Any new reusable code components that are being created should be done in Swift (they should be Objective-C compatible if you intend to use this code in Objective-C projects).
  3. If any part of a product is going to undergo heavy change, either due to a bug fix or a new feature. This is a good time to convert it into Swift.

A good example is how Apple is approaching the process of migrating to Swift. They are doing it component by component.

I have been developing apps in Objective-C for some time. I am able to create any reasonably complicated app now. If Objective-C hasn’t been deprecated then should I start making apps in Swift?

This is a choice that you have to make. It is recommended that new apps (at the very least) be made in Swift as that is the language that will undergo the maximum amount of changes & improvements in the future.

What do you suggest as a trainer?

Another question that I get very often. It depends on the situation. I would say learn both Swift & Objective-C. You can skip learning Objective-C if you are confident that you will not have to work with any projects written in that language.

If I am starting on a brand new project I would use Swift. But if its an Objective-C project I would stick to Objective-C.

Can Swift development only be done on macOS?

No! Swift development can also be done on Linux. However, iOS/macOS/tvOS/watchOS App Development can only be done on macOS through Xcode.

How should I migrate to Swift?

There are different approaches that one can use. It all depends on the situation and needs of your organisation. Here are some things that you can do:

  • Start development of brand new apps (from scratch) in Swift.
  • If you are creating a brand new library which will be used for future projects then go ahead with Swift.
  • If a major component of an existing app is going to be changed significantly then you can go ahead with Swift.

You can do all or some of the above. There may be other strategies too. You should also factor in the cost of migration from one language to another.