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.

Advertisements

Migrating to Swift from Objective-C

This article explores some of the advantages and challenges faced by developers while migrating to Swift from Objective-C.

1. Do we want to migrate?

Before you start the migration process remove the old adage:

If it isn’t broken, don’t fix it!

Start by identifying the reasons why you wish to migrate. Here are some possible reasons why.

  • The code is old and not updated for a very long time. You now wish to add new features.
  • The frameworks/libraries you are using in your project have upgraded to modern Swift and no longer support your old Objective-C syntax. *You may still want to just update to modern Objective-C, but this would be a good time to jump onto swift.
  • You see potential for improvement in code size/speed/performance by using new Swift features not available in Objective-C. For example: Generic Programming.
  • The developers who developed the app in Objective-C have left and the new employees are proficient at Swift. *Again not a strong reason, but a valid reason if there is no other alternative. Asking people to sit down and learn Objective-C may not be practical, especially if they don’t have a background in C Programming.
  • The app is due for a performance, stability, & bug fix update. This is a good time to consider migration to Swift.

Factors to keep in mind before considering migration.

  • The cost of migration. This is the cost of keeping a certain number of developers occupied in migrating the code. The cost is in terms of time as well as money.
  • Potential risks. Any change to the code increases the risk of bugs. The chances of introducing limits on backward compatibility also increase.
  • Benefits gained. An assessment needs to be done as to whether there are any benefits of migrating to Swift. The Return on Investment needs to be figured out.
  • Compatibility with 3rd Party or in house libraries that you might use.

After having thought through all this you are ready for the next step: “Prepare to Migrate”

2. Preparing to Migrate

This is where you actually begin to work on the migration of the App.

  1. As a first step perform a full code review of the app.
  2. The next step is a major decision. Should you rebuild your entire app from scratch or do a piece by piece migration. We will explore the advantages a little later in the article.
  3. Look for Swift versions of 3rd frameworks/libraries you use. This is not strictly required, however, this is a good time to check for new APIs.
  4. Identify parts of the project to migrate. This is to be done if it is a piecemeal migration. This marks you as ready for the next step: “Starting the Migration”.

3. Starting the Migration

Once you have everything in place you are ready to begin.

Migrations happen class by class. Select an Objective-C class to migrate and start working on converting it to Swift.

If you have any pure C functions then you can either choose to make them work with Swift or rewrite them in Swift.

While migrating pay special attention to your code. Here are some conversions that you can make.

  • See if you can make it simpler by using Generic Programming instead of usingVoid *
  • Replace the use of NSError * with exceptions.
  • Use extensions to give types new capabilities.
  • Consider creating your own Data structures. You may use Swift Arrays, Dictionaries if you wish. But this might be a good time to improve performance by building your own data structures.
  • Embrace closures and protocols a lot more.
  • Make extensive use of the @available attribute to describe your changes and mark availability
  • Start incorporating Swift Markup to make the comments from your Objective-C code more readable.
  • Enums pulled in from Objective-C can be made more powerful in Swift by adding methods which work with enums as a part of the enum itself.
  • Use property observers to make code more reactive. In some situations this might be easier than setting observers.

Migration Steps

Here are some general steps you can follow. The steps below are for both a full app conversion or a piece meal conversion.

Note: The steps mentioned below are sample steps and not necessarily the only way to achieve this.
  1. If its a full app conversion then create a new project. Else duplicate the existing project.
  2. Start by looking for the frameworks you need and importing them in the necessary Swift files.
  3. Identify class(es) that you have in your Objective-C project. Start by creating empty versions of those in your Swift project. It is very likely that you may not need all the classes as you might be optimising or reworking your App’s architecture. Also it is possible that you may need new classes.
  4. Next identify data structures used in the class. Either convert them to their swift equivalents or explore other options.
  5. Migrate the functions directly associated with the data structures.
  6. Migrate the variables used in the Objective-C class.
  7. Lastly migrate the remaining functions to Swift.
  8. Do this till you have converted all the classes that you wish to convert.

One point left to talk about is testing. Thoroughly test you app after each step you complete. If you are using XCTests, migrate a single Unit test at a time. Corresponding to the changes that you have made above.

5. Things to watch out for

There are many things to keep in mind while migrating your code.

  • In a mixed language project (Swift and Objective-C) Swift only features won’t be supported. So Generic Programming cannot be implemented.
  • Blind copying of the code from Objective-C to Swift may not result in the best output. Try to examine each line for potential optimisation opportunities.
  • Watch out for OS version compatibility. You may have to choose your Swift version accordingly.

6. Full Conversion versus Part by Part Conversion

Full Conversion

PROS:

  • The advantage of building the app from scratch is that your overall development time is less as different parts of the app can be refactored at development time.
  • You also have the advantage of adopting new development approaches or architectures such as Model View View Model (MVVM) or Test Driven Development (TDD).
  • You are in a better position to take advantage of all the Swift features as there won’t be any challenges with compatibility.
  • The advantages of Swift viz: Speed, Safety, and compact code are more easily achieved
  • If you want to support older versions of iOS then having a pure Swift and pure Objective-C version helps.

CONS:

  • Of course this means that your development time is large.
  • There is a potential for writing duplicate code in Swift especially if it is being reused in Objective-C projects. You may end up with 2 code bases for the same feature.

Part Conversion

PROS:

  • The advantage of migrating parts of your app is that you can split the migration over a larger period and use your resources on other projects.
  • In terms of cost this is less expensive and more resource friendly
  • The potential for duplicate code is reduced

CONS:

  • But on the flip side every time you take a new part to migrate you will have to make changes to the Swift code written earlier. This increases the development time and may affect the quality of the app in the long run.
  • You cannot take advantages of all the Swift features.
  • There is a chance that once the migration is complete the App may have to undergo an overhaul to take advantage of the Swift features & improve on Speed, Safety & Size.

This article just talks about some of the advantages and challenges with Migration to Swift. There are multiple approaches available and you will have to pick and choose the approach based on your needs or situation. I had written an article some time back about choosing between Swift & Objective-C, you can have a look at that too. Here is an article, for your reference, written by Apple on Migrating to Swift. Good luck & Happy Programming! Do feel free to share your experience migrating to Swift.

 

Using Swift Package Manager

About Swift Package Manager

The Swift Package Manager is the tool used to build Applications and Libraries. it streamlines the process of managing multiple Modules & Packages. Before we go ahead and learn to use Swift Package Manager we need to get familiar with some basic terminology.

Modules

Modules are used to specify a namespace and used to control access to that particular piece of code. Everything in Swift is organised as a module. An entire app can fit into a module or an app can be made using multiple modules. The fact that we can build modules using other modules means that reusing code becomes a lot easier. So, when we make an iOS App with Xcode and Swift. The entire app is considered a single module.

Targets

Targets are the end product that we want to make. So an app for iOS is a separate target. A library is a target. An app for macOS is a separate target. You can have many targets. Some can be for testing purposes only.

Packages

Packages group the necessary source files together. A package can contain more than one target. Normally one would create a package for a family of products. For example: you want to make a photo editing app that runs on macOS & iOS. You would create one package for it. That package would have 2 targets: an iOS App & a macOS App.

Products

This is a categorisation of your packages. There are 2 types of products. Executables or Libraries. A library contains the module which can be reused elsewhere. Executables are application that run & may make use of other modules.

Dependencies

Dependencies are the modules or the pieces of code that are required to make the different targets within the package. These are normally provided as URLs.

End Products

*NOTE: Before you get started you must be familiar with Setting up Swift on Linux. If you haven’t done that then please go through the updated article: UPDATE: Swift on Linux. This also makes use of Swift Package Manager.

Example

So let us get started with an example. We are going to learn how to create:

  • a library package called ErrorTypes
  • a library package, called MathOperations, that uses the ErrorTypes library package
  • an executable package called Calc that makes use of the MathOperations package.

We will see how to create all three elements. Also I have uploaded the ErrorTypes & MathOperations packages to the http://www.github.com repository to demonstrate the use of dependencies. You can also create your own local git repositories if you wish.

To illustrate the folder hierarchy: I have created a folder called “Developer” in my Ubuntu linux home folder. Within that I have created a folder called “SPMDEMO“. All the paths that I will be using will be with reference to these folders. You should see a structure like this:

/home/admin/Developer/SPMDEMO/ErrorTypes
/home/admin/Developer/SPMDEMO/MathOperations
/home/admin/Developer/SPMDEMO/Calc

You are free to follow this exercise using your own folder locations. Just modify the paths accordingly.

swift package init
swift package init --type executable
swift build

If you need help with the commands run:

swift package --help
swift --help

Creating a Package

  1. First let us start off by creating the ErrorTypes package.
    mkdir ErrorTypes
  2. Navigate to the folder and create the package:
  3. cd ErrorTypes
    swift package init
    

    By default init will create a library package type.

  4. Navigate to the folder containing the source files:
    cd ./Sources/ErrorTypes/
  5. Open the ErrorTypes.swift file and write the following code
    public enum ErrorCodes : Error
    {
         case FileNotFound(String)
         case DivideByZero(String)
         case UnknownError(String)
    }
    
    public struct MathConstants
    {
         static let pi : Float = 3.14159
         static let e  : Float = 2.68791
    }
    

    Feel free to add some code of your own. The above is just an example.

  6. Run the command to build to make sure that there aren’t any issues. You shouldn’t have any as there are no dependencies of any kind. Its a simple straightforward piece of code.
    swift build
  7. If everything is fine check your code into a git repository. This can be local or on the web. Remember that we will need the URL to this repository.
  8. Navigate back to the SPMDEMO folder.
    cd ~/Developer/SPMDEMO/
  9. Create a folder called MathOperations.
    mkdir MathOperations
  10. Navigate to the newly created folder and run the command to create a library package.
    cd MathOperations
    swift package init
    
  11. Navigate to the sources folder:
    cd ./Sources/MathOperations/
  12. Open the MathOperations.swift file and write the following code.
    import ErrorTypes
    
    public struct MathOperations
    {
         public static func add(Number num1 : Int, with num2 : Int) -> Int
         {
              return num1 + num2
         }
    
         public static func mult(Number num1 : Int, with num2 : Int) -> Int
         {
              return num1 * num2
         }
    
         public static func div(Number num1 : Int, by num2 : Int) throws -> Int
         {
              guard num2 > 0
              else
              {
              throw ErrorCodes.DivideByZero("You are dividing by zero. The second argument is incorrect.")
              }
    
              return num1 / num2
         }
    
         public static func sub(_ num1 : Int, from num2 : Int) -> Int
         {
              return num2 - num1
         }
    }
    
  13. Before we build we need to modify the Packages.swift file to indicate there is a dependency.
    Notice that in the MathOperations.swift file we are importing a module called ErrorTypes. We just created it. But just because we created it doesn’t mean it will be added automatically. We need to pull that module into our own

    Also notice that I have provided access specifiers “public” everywhere. This ensures that the code written in one module is accessible in the other.

    Navigate to the MathOperations parent folder.

    cd ~/Developer/SPMDEMO/MathOperations/
  14. Open the Packages.swift file and make the changes as shown below:
    // swift-tools-version:4.0
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(name: "MathOperations",
         products: [
              // Products define the executables and libraries produced by a package, and make them visible to other packages.
              .library(name: "MathOperations", targets: ["MathOperations"]),
         ],
    
         dependencies: [
              // Dependencies declare other packages that this package depends on.
              .package(url:"https://github.com/AmaranthineTech/ErrorTypes.git", from:"1.0.0"),
         ],
    
         targets: [
              // Targets are the basic building blocks of a package. A target can define a module or a test suite.
              // Targets can depend on other targets in this package, and on products in packages which this package depends on.
              .target(name: "MathOperations", dependencies: ["ErrorTypes"]),
              .testTarget(name: "MathOperationsTests", dependencies:   ["MathOperations"]),]
    )
    
  15. Once these changes are made save the file and run the command
    swift build

    If you typed everything correctly then you should see the source code for the ErrorTypes module being pulled in and the build being successful.Here are some common mistakes:
    – Forgetting to write the import ErrorTypes statement
    – Error in the URL
    – The from tag not matching the tag in the repository
    – Access specifiers are incorrect or missing
    – Not mentioning the dependencies in the target

  16. Just like with the ErrorTypes module create a git repository for the MathOperations module.
  17. Now let us make the Calc executable that will use the MathOperations library. First navigate back to the SPMDEMO folder and create a folder called Calc.
    cd ~/Developer/SPMDEMO/
    mkdir Calc
    
  18. This time we are going to create an executable package. Run the command:
    swift package init --type executable

    This also creates a similar folder structure as in the case of the library.

  19. Navigate to the folder containing the main.swift file.
    cd ./Sources/Calc/
  20. Modify the main.swift file as shown below:
    import MathOperations
    
    //testing addition
    var result : Int = MathOperations.add(Number: 33, with: 29)
    print("Result of adding 33 with 29 is: \(result)")
    
    //testing multiplication
    result = MathOperations.mult(Number: 33, with: 29)
    print("Result of multiplying 33 with 29 is: \(result)")
    
    //testing division
    do
    {
         result = try MathOperations.div(Number: 33, by: 0)
         print("Result of dividing 33 by 29 is: \(result)")
    }
    catch let error
    {
         print("ERROR: \(error)")
    }
    
    //testing subtraction
    result = MathOperations.sub(3, from: 29)print("Result of subtracting 3 from 29 is: \(result)")
    
  21. Navigate back to the main Calc folder.
    cd ~/Developer/SPMDEMO/Calc/
  22. Modify the Packages.swift file as shown below:
    // swift-tools-version:4.0
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(name: "Calc",
    dependencies: [
         // Dependencies declare other packages that this package depends on.
         .package(url: "https://github.com/AmaranthineTech/MathOperations.git", from: "1.0.1"),
    ],
    targets: [
         // Targets are the basic building blocks of a package. A target can define a module or a test suite.
         // Targets can depend on other targets in this package, and on products in packages which this package depends on.
         .target(name: "Calc", dependencies: ["MathOperations"]),
    ]
    )
    
  23. Save the file and run the build command:
    swift build
  24. Like before you should see both the MathOperationsErrorType module being pulled in. We are ready to run the executable. Navigate to the debug folder which contains the executable. Make sure you are in the main Calc folder when you run this command.
    cd ./build/debug/
  25. You should see an executable file called Calc. Run it.
    ./Calc
  26. If everything went okay then you should see the output on the console.

As you can see it is pretty straightforward to develop Applications written in Swift on Linux.

Adding System Modules

In the previous example we saw how to import our own custom made modules. However, there are some modules provided by the system which offers functionality we may wish to use. For example if we wanted to use the random number generator in our application we would need to use the random() method. This is in the glib module.

  1. Quickly create a package called SystemLibs. This is an executable.
  2. Write the following code in the main.swift.
    #if os(Linux)
    import Glibc
    #else
    import Darwin.C
    #endif
    extension Int
    {
         func toString() -> String
         {
              return "\(self)"
         }
    }
    
    var luckyNumber : Int = Int(random())
    
    var luckyNumberStr : String = luckyNumber.toString()
    
    print("The lucky number is \(luckyNumberStr)")
    
  3. Build the code and run the executable.

Adding system modules is direct and simple. The glibc module contains aspects of the standard library. The condition check is to make sure that we are importing the correct module based on the system that we are developing the application on.

Handling Sub-dependencies

As we saw in the earlier example, sub dependencies are handled automatically. So when our Calc application marked the MathOperations module as a dependency it was pulled during the build. However, the MathOperations module itself marked ErrorTypes module as a dependency. We did not have to modify the Packages.swift file belonging to Calc to indicate that ErrorTypes module also needs to be pulled. This was handled automatically by Swift Package Manager.

Conclusion

In this article we have seen:

  • How to create a library package
  • How to create a library package that depends on another library package
  • How to create an executable that depends on a library package
  • How to import the system Glibc module into our executables.

The Swift Package Manager simplifies many aspects of the development process for us. Many of the things we have discussed also work on macOS. Going forward reusing code and planning for the same should be done keeping Swift Package Manager in mind.

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

Programming Style Guide: Code Refactoring

One of the key attributes towards code that is readable and easy on the eyes is code that is split into appropriately sized pieces. Code refactoring is does exactly that. It is very easy to write a program as one big piece of code. Of course, any program that grows becomes increasingly complicated and highly inefficient. If not controlled, it will soon reach a point where it is highly unreadable, extremely difficult to maintain & filled with bugs. Not to mention that it is inefficient too.

Refactoring code and breaking it down into smaller reusable chunks is the key. The objective is:

  1. To make code easier to read
  2. To make reusable components so that we can save on duplication of code. This will reduce the code count and make sure that any changes to the reused code are available everywhere.
  3. To lend a structure to the application. Tasks now have their own space.
  4. Build scalable and maintainable code.
  5. Build bug free code.

Let us look at an example.

Screen Shot 2017-10-16 at 11.26.26 AM

Bad Code

This code is clearly written poorly. Its difficult to read. There aren’t good whitespaces. No consistency. Even the naming conventions are poor.

The fix would be :

  • Break it down into different functions
  • Separate tasks into their own files
  • Name the different elements of the code properly.

This is how the code looks now. It has been broken down into different files.

main.cpp

#include <iostream>
#include "MathOperations.hpp"
#include "Choices.hpp"

int main(int argc, const char * argv[])
{
     float number1           = 0.0;
     float number2           = 0.0;
     Choices selectedOption  = CLEAR;
     float answer            = 0;
     float integralAnswer    = 0;

     while(EXIT != selectedOption)
     {
          //Welcome message
          std::cout<<"Welcome to Calculator Program"<<std::endl;
          std::cout<<"Choose between the following options"<<std::endl;
          std::cout<<"1. Add\n2. Subtract\n3. Multiply\n4. Divide\n5. Remainder\n6. Percentage"<<std::endl;

          //User choice
          std::cout<<"Choice: ";                               std::cin>>selectedOption;

          //Chance to enter first number
          std::cout<<"Number 1: ";                               std::cin>>number1;

          //Chance to enter second number
          std::cout<<"Number 2: ";                               std::cin>>number2;

          switch (selectedOption)
          {
               case ADDITION:
                    answer = addition(number1, number2);
                    std::cout<<"The addition of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case SUBTRACTION:
                    answer = subtraction(number1, number2);
                    std::cout<<"The subtraction of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case MULTIPLICATION:
                    answer = multiplication(number1, number2);
                    std::cout<<"The multiplication of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case DIVISION:
                    answer = division(number1, number2);
                    std::cout<<"The division of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case REMAINDER:
                    integralAnswer = remainder((int)number1, (int)number2);
                    std::cout<<"The remainder of "<<number1<<" divided by "<<number2<<" = "<<integralAnswer<<std::endl;
                    break;
               case PERCENTAGE:
                    answer = percentage(number1, number2);
                    std::cout<<"The percentage of "<<number1<<" out of "<<number2<<" = "<<answer<<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><std::endl;
                    break;
               default:
                    break;
          }
     }
     return 0;
}

Choices.hpp

#ifndef Choices_hpp
#define Choices_hpp

#include <stdio.h>
#include <iostream>

enum Choices : unsigned short int { ADDITION = 1, SUBTRACTION, MULTIPLICATION, DIVISION, REMAINDER, PERCENTAGE, CLEAR, EXIT};

typedef enum Choices Choices;

std::istream& operator >>(std::istream &is, Choices& enumVar);

#endif

Choices.cpp

#include "Choices.hpp"

std::istream& operator >>(std::istream &is, Choices& enumVar)
{
    unsigned short int intVal;
    is>>intVal;
    switch (intVal) {
        case 1:
            enumVar = ADDITION;
            break;
        case 2:
            enumVar = SUBTRACTION;
            break;
        case 3:
            enumVar = MULTIPLICATION;
            break;
        case 4:
            enumVar = DIVISION;
            break;
        case 5:
            enumVar = REMAINDER;
            break;
        case 6:
            enumVar = PERCENTAGE;
            break;
        default:
            enumVar = EXIT;
            break;
    }
    return is;
}

MathOperations.hpp

#ifndef MathOperations_hpp
#define MathOperations_hpp

#include <stdio.h>

//Addition
float addition(float number1, float number2);

//Subtraction
float subtraction(float number1, float number2);

//Multiplication
float multiplication(   float number1, float number2);

//Division
float division(float number1, float number2);

//Remainder
int remainder(int number1, int number2);

//Percentage
float percentage(float number1, float number2);

#endif

MathOperations.cpp

#include "MathOperations.hpp"

//Addition
float addition(float number1, float number2)
{
    return number1 + number2;
}

//Subtraction
float subtraction(float number1, float number2)
{
    return number1 - number2;
}

//Multiplication
float multiplication(   float number1, float number2)
{
    return number2 * number1;
}

//Division
float division(float number1, float number2)
{
    if (number2 > 0) {
        return number1 / number2;
    }
    return 0.0;
}

//Remainder
int remainder(int number1, int number2)
{
    return number1 % number2;
}

//Percentage
float percentage(float number1, float number2)
{
    if (number2 > 0) {
        return (number1 / number2) * 100.0;
    }
    return 0.0;
}

Let us look at how this looks for Swift.
main.swift

import Foundation

var number1 : Float             = 0.0
var number2 : Float             = 0.0
var selectedOption : Choices    = Choices.CLEAR
var answer : Float              = 0.0
var integralAnswer : Int        = 0

func readNumbers(One firstNumber : inout Float, Two secondNumber : inout Float)
{
     //Chance to enter first number
     print("Number 1: \n")
     firstNumber = Choices.inputNumbers()

     //Chance to enter second number
     print("Number 2: \n")
     secondNumber = Choices.inputNumbers()
}

while(Choices.EXIT != selectedOption)
{
     //Welcome message
     print("Welcome to Calculator Program")
     print("Choose between the following options")
     print("1. Add\n2. Subtract\n3. Multiply\n4. Divide\n5. Remainder\n6. Percentage")

     //User choice
     print("Choice: \n")
     selectedOption = Choices.inputChoices()
     switch (selectedOption)
     {
          case Choices.ADDITION:
               readNumbers(One: &number1, Two: &number2)
               answer = addition_of(_value: number1, with_value: number2)
               print("The addition of \(number1) & \(number2) = \(answer)")
               break
          case Choices.SUBTRACTION:
               readNumbers(One: &number1, Two: &number2)
               answer = subtraction_of(_value: number1, from_value: number2)
               print("The subtraction of \(number1) & \(number2) = \(answer)")
               break
          case Choices.MULTIPLICATION:
               readNumbers(One: &number1, Two: &number2)
               answer = multiplication_of(_value: number1, with_value: number2)
               print("The multiplication of \(number1) & \(number2) = \(answer)")
               break
          case Choices.DIVISION:
               readNumbers(One: &number1, Two: &number2)
               answer = division_of(_value: number1, by_value: number2)
               print("The division of \(number1) & \(number2) = \(answer)")
               break
          case Choices.REMAINDER:
               readNumbers(One: &number1, Two: &number2)
               integralAnswer = remainder_of(_value: Int(exactly:number1)!, <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>divided_by_value: Int(exactly: number2)!)
               print("The remainder of \(number1) divided by \(number2) = \(integralAnswer)")
               break
          case Choices.PERCENTAGE:
               readNumbers(One: &number1, Two: &number2)
               answer = percentage_of(_value: number1, with_respect_to_value: number2)
               print("The percentage of \(number1) out of \(number2) = \(answer)")
               break
          default:
               selectedOption = .EXIT
               break
     }
}

Choices.swift

import Foundation

enum Choices { case ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, REMAINDER, PERCENTAGE, CLEAR, EXIT}

//CLI Reading Capability
extension Choices
{
    static func inputChoices() -> Choices
    {
        let ip : String? = readLine()
        let choice : String = String(ip!)

        switch choice {
        case "1":
            return .ADDITION
        case "2":
            return .SUBTRACTION
        case "3":
            return .MULTIPLICATION
        case "4":
            return .DIVISION
        case "5":
            return .REMAINDER
        case "6":
            return .PERCENTAGE
        default:
            return .EXIT
        }
    }

    static func inputNumbers() -> Float
    {
        let ip : String? = readLine()

        let numberFormatter = NumberFormatter()
        let number = numberFormatter.number(from: ip!)

        let num : Float? = number?.floatValue
        return num!
    }
}

MathOperations.swift

import Foundation

//Addition
func addition_of(_value number1 : Float, with_value number2 : Float) -> Float
{
    return number1 + number2;
}

//Subtraction
func subtraction_of(_value number2 : Float, from_value number1 : Float) -> Float
{
    return number1 - number2;
}

//Multiplication
func multiplication_of(_value number1 : Float, with_value number2 : Float) -> Float
{
    return number2 * number1;
}

//Division
func division_of(_value number1 : Float, by_value number2 : Float) -> Float
{
    if (number2 > 0) {
        return number1 / number2;
    }
    return 0.0;
}

//Remainder
func remainder_of(_value number1 : Int, divided_by_value number2 : Int) -> Int
{
    return number1 % number2;
}

//Percentage
func percentage_of(_value number1 : Float, with_respect_to_value number2 : Float) -> Float
{
    if (number2 > 0) {
        return (number1 / number2) * 100.0;
    }
    return 0.0;
}

Discussion on Swift Extensions

As we can see that most of the code in Swift is very similar to C++. Most of the differences are basic syntactic differences. However, there is 1 feature of Swift that greatly aids code refactoring that I would like to talk about, Extensions.

Extensions allow us to add new functionality to the existing type. As the name says the type is extended. This allows us to add changes to a type in a consistent & clearly demarcated way. Developers can now neatly separate newly added components. This greatly helps in understanding the evolution of types.

“This is often referred to as versioning.”

Extensions can be used in the following ways to implement code refactoring:

  • Different sections of a type reside in their own extensions
  • Changes made to a type are made by keeping them in their own extensions
  • Step by step build up of code is done by representing each step as an independent extension. This gives clarity on how a certain end result was achieved.

Conclusion

As we can see from the sample code above (for both C++ & Swift) the program is much more readable. Code is carefully compartmentalised. Its a lot easier to read. It is a lot easier to scale too.

The reader may point out that the amount of code to achieve the same result is significantly higher, that however is a small price to pay in the long run. The biggest advantage is the scalability & the ease with which it can be done. Simply breaking code down into separate files & functions makes a huge difference. Here are some other benefits:

  • Individual files can be modified. This means one can now have a team working on different parts of the code.
  • Code is less cluttered. Changes are now spread across files & are easier to track.

We will now see how we can further improve this code in upcoming articles.

Programming Style Guide – The Need for programming standards

Programming Style Guide refers to the conventions followed while writing programs. This guide is going to be a series of blogs highlighting different programming standards. The series will try to cover as many standards as possible, focus will be on common and popular standards.

But why the need for programming standards? Standards help software developers design software in such a way that it is easy to read, understand, maintain & expand. It provides a consistent experience & also speeds up the way in which software development is done.

A program written with the best standards kept in mind is self explanatory, easy to read, can be built on, & is a stable piece of software

This specific article will act as a Content list for all the articles written as a part of this series. The examples are from the Swift & C++ programming languages.

  1. Naming Conventions
  2. Code Refactoring
  3. Programming Style Guide: Documentation
  4. Programming Style Guide: Command Query Separation

 

 

Programming Style Guide: Naming Conventions

Today we are going to look at Naming conventions you can follow while writing code.

Naming conventions lay down the basic rules for naming different elements in your code. The objectives are simple:

  • Make the element easy to read
  • Should be self explanatory
  • Should contain information in a compact and concise manner.

Ideally a well named variable or function should not need a comment to explain what it is for.

With the above objectives in mind let us look at some of the naming conventions that can be followed. The examples are from the Swift & C++ programming languages.

Naming Conventions

Camel Case Names

In camel case naming convention the entire name of the element is constructed by forming a sentence joined into a single word. So for example if we have a variable for keeping track of the price of oil in US dollars then the variable name might be priceOfOilUSD.

Here are some examples of naming conventions with the camel case.

SWIFT

var priceOfOil : Float = 23.49

C++

float priceOfOil = 3.45;
class PersonInfo
{

};

Underscore Separated Names

In the underscore separated naming convention the entire name of the element is constructed by forming a sentence joined together with the help of underscores in-between them. So if we take the example of the variable keeping track of the price of oil in US dollars the the variable name might be price_of_oil_usd.

Swift

var price_of_oil : Float = 45.71

C++

float price_of_oil = 99.87;

void print_value_of_pi()
{
     //print something
}

Names with type information

A naming convention that is quite popular is the one that mixes the previous 2 naming conventions, with the underscore used to separate the type description in the prefix. So if we take the example of the variable keeping track of the price of oil in US dollars then the variable name might be f_priceOfOil or float_priceOfOil. Either of the design styles work. The prefix is popularly abbreviated and you can create your own rules for abbreviating the type description.

This style is often referred to as the Hungarian notation. The additional information that is provided as a part of the prefix can be:

  • Whether the variable is a pointer
  • Whether the variable is an object
  • The scope of the variable
  • Type size
  • Whether the data can vary or is a constant

Swift

var f_priceOfOil : Float = 0.0

C++

float f_priceOfOil = 22.3;
int *ptr_memmoryBuffer = NULL; //ptr indicates variable is a pointer

Naming Rules

There are some rules that are typically followed while designing names for variables and  functions. Like the conventions themselves the rules are not binding but they are very useful an give the added punch that naming conventions provide.

  1. Variable names always start in lower case.
  2. Type names always start in upper case.
  3. The naming conventions is consistently applied through all the projects
  4. Names should be kept as small as possible without sacrificing on the description

Naming Strategies

As far as strategies are concerned there are multiple approaches that one can follow. Here are some potential strategies.

  • Follow one naming convention for variables and another convention for functions.
  • Let constants be all upper case
  • Prefix types with your companies initials.

Summary

The above illustrate just some of the naming conventions that can be followed. By no means are they comprehensive or complete. Also it is not necessarily true that everyone follows the above naming conventions. You may find that many software development firms have their own unique naming convention. This article should give you an an idea about naming conventions. Feel free to share some naming conventions that you have come across.