Swift reflection about food

Reflection in practice

Reflection technique may be useful to build quasi generic functions that operate at runtime. It may be quasi type safe, though it uses runtime too - as such can't be optimised/validated during compilation. With Objective-C we used <runtime/objc.h> and do all the things. In Swift it's just complicated.

I'm not going to explain here in details what the reflection is and how it works, there are cool projects already (check out Mirror) and plenty of blog posts about this. What I'll demonstrate here is simply "for fun", and educational purpose.

Goal

The goal is to calculate (dynamically, without anonymous strings) sum of properties (variables) out of struct or class.

For this excercise I'll work with food. The Meal object consisting of nutrients, and I'll calculate sum of nutrients in collection of meals.

The meal

Meal describes single meal. Meal consists of calcium and fat, which is defined by NutrientsType protocol

struct Meal: NutrientsType {  
    var calcium: Int
    var fat: Int
}

NutrientsType

to abstract code a little, for any meal I defined NutrientsType there is protocol with defined nutrients and with function total(...)

protocol NutrientsType {  
    var calcium: Int { get }
    var fat: Int { get }
}

next thing is NutrientsType.total(...) function. This function sum nutrient values from the list of meals and return the value. With help of type Mirror I can access to the list of variables of struct or class, then use it to access the value.

extension NutrientsType {  
    static func total(meals: [Self], nutrient: Nutrients) -> Int {
        return meals.reduce(0) { (sum, meal) -> Int in
            for child in Mirror(reflecting: meal).children where child.label == nutrient.rawValue {
                let valueMirror = Mirror(reflecting: child.value)
                if valueMirror.subjectType == Optional<Int>.self {
                    return sum + ((valueMirror.children.first?.1 as? Int) ?? 0)
                } else {
                    return sum + (child.value as! Int)
                }
            }
            return sum
        }
    }
}

Nutrients

To escape from string identifiers (we don't like anonymous string labels in Swift) I defined possible nutrients, like Calcium and Fat, with enum:

enum Nutrients: String {  
    case calcium, fat
}

this way I can validate anonymous input data: I can't use any string label to identify variable in my struct or class.

All together

The best part is here. For given list of meals I calculate sums:

let meal1 = Meal(calcium: 3, fat: 30)  
let meal2 = Meal(calcium: 13, fat: 20)  
Meal.total([meal1, meal2], nutrient: .fat)  

need more magic? there you go. Defining this simple extension to Array type:

extension Array where Element: NutrientsType {  
    func total(nutrition: Nutrients) -> Int {
        return Element.total(self, nutrition: nutrition)
    }
}

I can calculate total fat value right of the array of meals

[meal1, meal2].total(.fat)

full source code is here

Conclusion

I don't know if this is that useful. I just found it interesting to know. I used reflection a lot in Objective-C but with Swift I'm trying to avoid that, or use demonstrated above techniques to hide dynamic nature of the code. What you see here is mixture of runtime and compile-time approach. Enum will check if input field names are valid, then it is used in runtime to map the values to actual struct or class. The ugliest part is dealing with Mirror, which is the reflection itself.