Wondering if there's a good way to do this or not:
I have a @propertyWrapper
named "Enhanced" that I use. I use the wrappedValue.set
to do some actions, and I would also like to do some further actions if the property is Equatable.
Currently, the code looks like this:
@propertyWrapper
class Enhanced<T: Equatable>: Codable
{
private var value: T
var projectedValue: Enhanced<T> { self }
var wrappedValue: T
{
get { value }
set { set(newValue, notify: nil) }
}
func set(_ proposedValue: T, notify: Bool?)
{
let oldValue = value
let newValue = proposedValue
let changed = newValue != oldValue
if changed { /* more magic here */ }
value = newValue
}
}
Now I would like to remove the Equatable
conformance over the generic T
, but still be able to compare the old and new values IF the generic T conforms to Equatable.
I've tried a handful of techniques, all of which dead end somewhere. My latest was this:
let changed: Bool
switch T.self
{
case let equatableType as any Equatable.Type:
if
let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = newEquatableValue != oldEquatableValue
}
default:
changed = true
}
...but the error is an understandable Binary operator '!=' cannot be applied to two 'any Equatable' operands
.
I tried different patterns to cast the generic type T into an Equatable and silently fail if the generic does not conform, but even if they do, the resulting "cast" types I get back aren't equatable themselves.
Any revelations to the proper pattern would be great!
After some deep web-sleuthing, I came across a snippet of code that does the magic I need:
(HT to neonichu/equalizer.swift on GitHub)
With this bit of pseudo type-erasure, I can make this work:
By using an extension on
Equatable
that does further casting of the values, this allows for these two values to be compared (and fail if they are not the same).Hope this helps someone else!