Does Swift's compiler know to optimise this second function call away?

Assuming I have a function body that contains

if let jsonDictA: [String: AnyObject] = try? jsonDictionary.valueForKeyPath(Field.things.rawValue) {
    objectsOfTypeA = mapToTypeA(from: jsonDictA)
} else {
    objectsOfTypeA = nil
}

// ...

if let jsonDictB: [String: AnyObject] = try? jsonDictionary.valueForKeyPath(Field.things.rawValue) {
    objectsOfTypeB = mapToTypeB(from: jsonDictB)
} else {
    objectsOfTypeB = nil
}

In both cases the same try? jsonDictionary.valueForKeyPath(Field.things.rawValue) happens, and jsonDictA would be the same as jsonDictB.

Does the compiler automatically optimise this away such that this cast happens only once, or is there a computational cost to this compared to instead doing:

if let jsonDictToMap: [String: AnyObject] = try? jsonDictionary.valueForKeyPath(Field.things.rawValue) {
    objectsOfTypeA = mapToTypeA(from: jsonDictToMap)
    objectsOfTypeB = mapToTypeB(from: jsonDictToMap)
} else {
    objectsOfTypeA = nil
    objectsOfTypeB = nil
}

Normal functions may have side-effects when they are called, so the compiler is forced to call valueForKeyPath twice if you wrote it twice.

If the function can be inlined — or if Swift ever gets the concept of a "pure" function — the compiler can potentially deduce whether there are side effects, and optimize some or all of the second call away.

FWIW, if this is the standard Obj-C function valueForKeyPath, the Obj-C runtime actually dispatches it to a different function chosen at runtime. (It's part of Obj-C's elaborate KVC mechanism.) It's about as un-pure a function as you can get. :slight_smile:

3 Likes

if Swift ever gets the concept of a "pure" function

Do I understand you correctly that Swift currently does not understand the concept of a pure function (although it could in theory in the future), and that it therefore would not treat a pure function differently – with regard to optimisations like the ones in my original question – than a largely equivalent one with side effects?

In this particular case it's not the standard Obj-C valueForKeyPath but a custom and project-specific Swift implementation that throws – so it's not pure either.

This is not quite right; the compiler understands the notion of a pure function¹, but it has to be able to see the function body to ascertain that the function is pure, because there is no language annotation that gives it this information directly.

If we add a pure annotation, the compiler would know if a function was pure solely from its interface, and the function body would not need to be visible to the compiler to make these optimizations. It sounds like in your case the function isn't pure anyway, so none of this would apply, and it really does have to be called twice.


¹ e.g. this simple example. You can see that the compiler optimizes away the first call to pure.

5 Likes

Thank you for the clarification. That’s what I expected.

I believe there are weird unofficial methods of telling the compiler that a function has no side-effects, but they don’t officially exist, are extremely easy to use incorrectly, and are extremely dangerous when used incorrectly.

I think some form of “pure” attribute would be very useful as well: I recently proposed such a property for the purpose of identifying declarations that could be evaluated at compile-time.

Terms of Service

Privacy Policy

Cookie Policy