Open
Description
The following expression looks valid but always returns nil
:
let retrievedValue: Int? = try? resolver.value(for: key)
A number of factors contribute to such an outcome:
FeatureFlagResolver
’svalue(for:)
method uses generics, and therefore cannot take advantage of Swift’s type inference—the output type should be specified externally;- The same method
throws
, and calls to it requiretry
,try?
, ortry!
, wheretry?
, which returns an optional, is nearly always the preferred option; - At the same time, feature flag values themselves cannot be optional: before returning a retrieved value, the resolver validates it, and throws
FeatureFlagResolverError.optionalValuesNotAllowed
is it’s an optional; - In the expression above,
Int?
is used to denotetry?
’s return type (always an optional) but is interpreted by the resolver as the type of the feature flag value; - The resolver sees an optional type and throws
FeatureFlagResolverError.optionalValuesNotAllowed
which is then silenced bytry?
(i.e. the error is replaced withnil
).
This issue only occurs when using try?
, and attempting to replace it with a do / try / catch
block to inspect the error (see below) does not help in reproducing it: inside a do
block, try
doesn’t return an optional, so the resolver is not confused about the type.
do {
let retrievedValue: Int = try resolver.value(for: key)
} catch {
print(error)
}
Right now, I see no clear solution to the problem, which allows preserve both generics and explicit errors in value(for:)
.
The following code works properly (and it’s actually used in FeatureFlag
). However, the fix is super unintuitive.
let retrievedValue = try? resolver.value(for: key) as Int