Since I have [Emoji] type annotation, I didn't think it would make any difference.
But I give it a try and very surprising result:
First, I change the first .init to Emoji of every element and the compile is about the same slow. Then I changed the second .init to Category and clean and. compile, first a window pop up saying:
"..run out of application memory. Quit some app ..."
Got you. That slowdown you saw before is probably due to VM trashing, just in that case the memory required didn't overflow available VM size (typically about machine RAM size x 2).
Another workaround that might work for you:
var allEmojis: [Emoji] = []
func initEmojis() {
allEmojis.removeAll()
allEmojis.append(.init(character: "π", name: "Grinning face", category: .init(group: "Smileys & Emotion", subgroup: "face-smiling"), isNew: false, zwjGroup: nil))
// repeat this 3772 more time
}
import Foundation
var allEmojis: [Emoji] = {
// just let it crash if something is wrong but shouldn't because
// we created the input and the output, everything should parse...
try! JSONDecoder().decode([Emoji].self, from: allEmojisJson.data(using: .utf8)!)
}()
private let allEmojisJson = """
.
.
.
Now the command line tool that generates this is very slow to compile. But my app now compile super fast and app startup is instant on device even with debug.
It's best to continue here to not mix the threads.
I confirm there's something odd going on here. Xcode consuming all those 10s or even 100s of GB and then crashing my computer (it did) is not good. I tried 4K of your lines with different permutations of explicit types vs ".init":
let emojis: [Emoji] = [
.init(character: "π", name: "Grinning face", category: .init(group: "Smileys & Emotion", subgroup: "face-smiling"), isNew: false, zwjGroup: nil),
// 4K of those
]
vs
let emojis: [Emoji] = [
Emoji(character: "π", name: "Grinning face", category: .init(group: "Smileys & Emotion", subgroup: "face-smiling"), isNew: false, zwjGroup: nil),
// 4K of those
]
vs
let emojis: [Emoji] = [
.init(character: "π", name: "Grinning face", category: Category(group: "Smileys & Emotion", subgroup: "face-smiling"), isNew: false, zwjGroup: nil),
// 4K of those
]
vs
let emojis: [Emoji] = [
Emoji(character: "π", name: "Grinning face", category: Category(group: "Smileys & Emotion", subgroup: "face-smiling"), isNew: false, zwjGroup: nil),
// 4K of those
]
the types:
struct Category {
var group: String
var subgroup: String
}
struct Emoji {
var character: String
var name: String
var category: Category
var isNew: Bool
var zwjGroup: String?
}
It would be extremely rare anyone would want to write 4K of such lines, but still, quadratic CPU time complexity aside, quite questionable memory complexity (like 10 MB per expression?!) is ... unexpectable to put it mildly. Highly likely there's a memory leak in there. It's a bug worth filing.
It would be extremely rare anyone would want to write 4K of such lines
Not by hands but code gen tools can often produce large boilerplate source. My case is pure data. Storing in json and decode at runtime is better to avoid slow Swift compile.
However, itβs better if Swift can just compile such code and avoid the extra decode and large json string.
There could also be the DoS angle here. For the record godbolt's compiler is killed with one error or another (when using explicit types vs .inits) - I guess in one case it's killed due to OOM situation and in another due to compiler spending too much time during the compilation.