Structs, part 2

Posted on Mon 17 February 2020 in swift

Another day of 100 Days of Swift in the books! Today I finished the section on structs. I'd forgotten a few things, so let's dive in.

In Objective-C, we typically implement lazy variables by making them computed properties, so I'm not used to thinking about these concepts separately. However, here's an attempt at a contrived example that includes both lazy variables and computed properties:

struct BaseData {
    var records: [String]

    init(from json: String) {
        let data = NSData(contentsOfFile: json)!
        let jsonArray = try! JSONSerialization.jsonObject(with: data as Data, options: .fragmentsAllowed)
        self.records = jsonArray as! [String]
    }

    var testTrainSplit: Int {
        return Int(Double(records.count) * 0.8)
    }

    var trainSet: ArraySlice<String> {
        return self.records.prefix(self.testTrainSplit)
    }

    var testSet: ArraySlice<String> {
        return self.records.suffix(from: self.testTrainSplit)
    }
}

struct TitanicDataset {
    lazy var data = BaseData(from: "titanic.json")

    // must be mutable because we're accessing a lazy variable
    mutating func train() {
        for record in self.data.trainSet {
            // train or something
        }
    }
}

Note that you can't use lazy variables on constant let instances of a struct. If you think about it for a minute, it'll make sense. Accessing the lazy property causes the instance to be modified when the property is finally initialized and assigned, and that's not allowed. This is also why the train() method of TitanicDataset has to be marked as mutating.