Design by Contract in Swift
Asked Answered
D

2

20

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?

Disagreement answered 4/8, 2015 at 19:11 Comment(10)
Interesting question. What do you mean by design-by-contract at compile time? Can you paste or reference an example in another language?Molasses
Yes and sure! Check out the edit.Disagreement
Swift has precondition and preconditionFailure, however they act almost like assert and assertionFailure. I am not aware of any way of doing Design by Contract in SwiftPiedadpiedmont
Well, isn't that sad? :(Disagreement
A script that processes the source files for contract comments and produces the equivalent XCTest files would be one way around built in language / IDE support.Eure
Hmm... Interesting thought. Could be a good project.Disagreement
I fear that the answer to the question as set is 'no'. But that's definitely not worth 50 points.Fonville
As far as I know Tommy is correct.Kaspar
If one were to design by contract in Swift, they would need refinement types. Considering Swift can't even do type inference in a timely manner in general (turns out Swift's unique mix of subtype inference is NP-complete) it's a bit of a stretch to think it can infer predicates ;)Defeasance
This is breaking my heart, you guys!Disagreement
U
14

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?

Upbuild answered 11/8, 2015 at 21:7 Comment(0)
S
-4

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))
Subak answered 11/8, 2015 at 18:9 Comment(4)
No, Edward, this is not what I want to do. The answer has got nothing to with design by contract. You can read about it here - en.wikipedia.org/wiki/Design_by_contractDisagreement
Interesting concept, so help me understand more about it, is it like function signature but without the protocol wrapper ? If thats the case, I don't think Swift has that kind of support yet, but I might be wrong.Subak
It is a type of Defensive Programming. Setting expectations as to what a function will do and what it is expected of the caller. By making these details explicit, the function is less prone to error since the specifications are explicit. Yes, Swift doesn't have a native support. But, libraries? Can be done? Cannot be done? That is the question.Disagreement
thanks for the clarification @avismara, Sorry i can't provide you with the help you needed.Subak

© 2022 - 2024 — McMap. All rights reserved.