The idea is that E is an enumeration. The constraints parameter is a list of values from that enumeration, and symbols map from enumeration values to strings.
For each enumeration value in constraints, if that enumeration value is a key in symbols, the associated string value should be in the returned list of strings.
The thing I can't figure out is how to define the type E. E should be valid iff it is an enumeration type. Is there any way to do this?
The check you're asking for isn't type safety, since you would allow any enum to be used. That doesn't prevent the caller from using an inappropriate type.
If you don't care which enum it is, why would you care if an arbitrary Hashable was used for E? Is there something inside foo that it makes a difference to? Wouldn't things just work fine inside foo if E is Int, for example?
If you want actual type safety, the thing to do is declare a protocol, say SymbolConstraint (which can be empty, for this purpose) and constrain E to require SymbolConstraint conformance.
That doesn't prevent a caller from intentionally using foo with something other than an enum that's force-conformed to SymbolConstraint (again: why does foo care?), but it does prevent them from unintentionally passing in a random Hashable.
Also, FWIW, for an enum without associated values on any of its cases, you can kinda make an "Is it an enum?" test by declaring it CaseIterable and requiring E to conform to CaseIterable. The compiler will synthesize the enum's conformance for you, and I don't think it's possible to make anything except an enum conform.
This helps. I wasn't aware of CaseIterable. This comes pretty close to what I was looking for:
class Foo<T: CaseIterable & Hashable> {
static func foo(symbols: [T: String], constraints: [T]) -> [String] {
var result = [String]()
for (symbol, string) in symbols {
if constraints.contains(symbol) {
result.append(string)
}
}
return result
}
}
enum Weather: CaseIterable {
case clear
case fog
case wind
}
let constraints = [Weather.fog, Weather.wind]
let symbols = [ Weather.clear : "Let's go!",
Weather.fog: "We must be in London",
Weather.wind: "Batten down the hatches!"]
let result: [String] = Foo.foo(symbols: symbols, constraints: constraints)
print(result)
foo is very curious, that it uses symbols ordering (which has no meaning of order), should the order of the result matchesconstraints instead (well, this still throws out nil value)?