I have some code where I want to create a Dictionary of document "styles", similar to CSS. I'll have keys like "font size", "font weight", "background color", "font family", etc. But the values for those keys are different types (Float, String, Color, etc). I'm wondering about the best way to do this, and if there is an Swifty idiom for this situation.
One option is that I could make things dynamic.
var styles: [StyleKey: Any]
enum StyleKey {
case fontSize, fontWeight, ...
}
But taking some inspiration from the PreferenceKey type in SwiftUI, I could try something more type-safe:
protocol StyleKey {
associatedtype Value
}
struct FontSize: StyleKey {
typealias Value = Float
}
// structs for other keys
The keys would be things like FontSize.self, and I could have lookup and setter functions like:
Thanks, I'll think about this. A possible downside is that it could take too much memory space. I don't have many keys, yet. (I'm not re-implementing all of CSS.) But I have styles attached to every node of a document tree, so if the key count gets higher, there will be a lot of nils in these structs.
You should follow @tera's suggestion: the style value can be an enum with associated values, and the dictionary contains enums with the appropriate values. Having a struct with every possible value is wasteful.
Note there's significant memory and CPU consumption overhead in any dynamic structure like Dictionary. In case of dictionary beside anything else there'll be a minimal hash table size. A simpler "struct Style" outlined by @Nickolas_Pohilets can easily win both by memory and by CPU consumption.
In this case, what is the type of Dictionary? Do you have one enum for keys, and another enum for the values? If I do something like this below, it's possible to pass mismatched keys and values. That's not the end of the world; but I'm trying to understand what you mean exactly.
enum with associated value is anti-OO pattern. It will need switch/case any where the enum value is operated on. There must be better option. Look into AttributedString to get some inspiration. It used DynamicMemberLookup. So you may not even need your dictionary. Let’s you set foregroundColor, backgroundColor, font etc. It has many different styling options thats extensible, it’s even user configurable(scriptable) with json5 syntax.
Can you elaborate on this? What's wrong with switch and case? Enumerations with associated values are very useful and the feature is loved by many programmers[1][2]. Types like Optional and Result are enumerations with associated values.
If you look at the actual source code for AttributedString (at least, the swift-corelibs-foundation version), you'll see that AttributedString internally contains an array of Int and [String: Any] to store attributes.
In this case, what is the type of Dictionary? Do you have one enum for keys, and another enum for the values?
Yes: a simple enum without any associated values for the keys, and an enum with associated values for the values. You can use dictionary subscripts to access the values.
The type of Dictionary would be something like [StyleKey : StyleValue]
not necessarily. there are hundreds of possible CSS property keys and if only a few are set at any given time, a Dictionary-based representation may easily win in terms of memory efficiency.