Home » Swift » Design by Contract in Swift

Design by Contract in Swift

Posted by: admin November 30, 2017 Leave a comment

Questions:

Does Swift provide a native Design by Contract support? I understand that it can be done during runtime through assertions, but could it be done during compile time? Or, are there any external plugins/libraries that do this?

EDIT

By saying “during compile time Design by Contract”, I do not mean the library to be an all powerful static analyser that C# has. It would be enough for me if it is something like the one that iContract provides for Java. Let us look at an example:

A DBC code for the square root evaluation in Java using iContract could be written as :

/** 
 * @pre f >= 0.0
 * @post Math.abs((return * return) - f) < 0.001 
 */ 
public float sqrt(float f) { ... } 

Now, this keeps my contract as a part of my API specification rather than a part of its implementation which I believe is a cleaner way. The caller will know what his responsibilities are and the callee is setting its expectation, all in albeit clearer manner. Do we have something like this in Swift?

Answers:

TL;DR

As @Tommy points out in the comments under your question, it would appear that the plain & simple answer to your question is “No, compile time DbC is not currently a feature of Swift”.


What’s built in right now?

For built-in support for this type of design strategy, you currently have to look at the runtime I’m afraid. Swift appears to prefer runtime assertions for enforcing preconditions currently, although the language seems generally to be putting more emphasis on safety at compile time (more on this below). The global functions assert, assertionFailure, precondition and preconditionFailure are designed to be sprinkled liberally throughout code without impacting release build performance.

Unit tests are, of course, another strategy for checking that API contracts are fulfilled, but these must be thought of and implemented manually, and so are error prone.

Something else that is perhaps interesting to note is that amongst the better documentation comment support of Swift 2, “requires”, “precondition” and “postcondition” are recognised markup keywords, such that they are displayed prominently in quick help documentation:

/// - precondition: f >= 0.0
/// - postcondition: abs((return * return) - f) < 0.001
/// - returns: The square root of `f`.
func sqrt(f: Float) -> Float { ... }

So does this emphasis on being able to provide good documentation for API contracts mean that the Swift development team clearly cares about it, and this is a stop-gap until they incorporate something into the syntax in the future, or does it mean that they think this sort of information belongs in the documentation? Pointless postulation, perhaps. Regardless, despite the fact it’s not proper DbC, I think it’s a handy thing to be aware of right now.

What can I do about it now?

With Objective-C, macros could be used to essentially implement basic DbC, however the lack of macros in Swift means you would have to resort to some kind of function/generics-based wrapper, which I think would look like a really awkward bodge.

Xcode’s support for adding custom scripts to a target’s build phases – as suggested by @JonShier in the comments – is perhaps the closest you will get to useful & automatic DbC without waiting for the language to (maybe / maybe not) introduce such a feature. With the aforementioned documentation markup keywords, a script that analyses documentation comments to build unit tests could even be incorporated retrospectively to projects with only a small amount of learning/effort on the part of the user. As you say, I think this could make a very interesting project!

Will it be a built-in feature in the future?

It is not clear whether or not native DbC might be incorporated into Swift in the future. Arguably, it is a feature that is well suited to the mission of the Swift language, which is to say that it promotes safer code and reduced risk of runtime errors. Should it become a part of the language, I would suggest that we would be more likely to see them appear as declaration attributes than as interpreted comment markup, for example:

@contract(
    precondition = f >= 0.0,
    postcondition = abs((return * return) - f) < 0.001
)
func sqrt(f: Float) -> Float { ... } 

(But that is just speculation, and of no use to us right now!)

From what I know of the topic, compile-time DbC can be a very complex problem. But who knows… work on the Clang Static Analyzer has certainly shown that there is an underlying desire to drag identification of runtime bugs back to compile time. Perhaps this is the perfect problem to put a Swift static analyser to work on in the future?

Questions:
Answers:

I’m not if this is what you’re looking for but here is a suggestion you could try maybe.
If you want to define a protocol where you can define the signature of the sqrt function and leave the implementation for other classes or structs to implement at a later point you could do something like the code below:

Note: the the sqrtf is just using the system implementation here.

public protocol Math {
    func sqrtf(f: Float) -> Float
}

struct NativeMath: Math {
    func sqrtf(f: Float) -> Float {
        return sqrt(f)
    }
}


println(NativeMath().sqrtf(2))