I have a struct Event that gets initialized with a time and a value.
The value property's type is decided at the time the event is created. It can be one of either an Int or Double primitive.
How should I implement this in Swift?
I want to be able to create a new Event object like so:
let event = Event(time: Date.init(), value: EventValue<Double>(40.3467))
I found this but I can't make it out.
I have experimented with so many permutations of this and the best I can do is
struct Event {
let time: Date
var value: EventValue? // This line 'requires arguments in <...>'
}
struct EventValue <T> {
let value: T?
}
Add generic parameter to your Event struct too and then use this type for parameter of EventValue
struct Event<T> {
let time: Date
var value: EventValue<T>?
}
then just initialize EventValue without specifing type, since compiler allows you to pass just value corresponding to generic parameter constraint. And since your parameter has no constraints, it is equal to Any, so you can pass any type
let event = Event(time: Date.init(), value: EventValue(value: 40.3467))
Since EventValue is generic, it can't be used directly as the type of a property.* You have to either directly specify the type parameter, which gives you a container that always has a particular variety of EventValue:
struct DoubleEvent { // Please pick a better name, though
let time: Date
var value: EventValue<Double>?
}
Or make the container generic as well:
struct Event<T> {
let time: Date
var value: EventValue<T>?
}
In either case, you don't have to explicitly give the type when creating an Event: let event = Event(time: Date(), value: EventValue(value: 40.3467)) Type inference will fill it in when the Event itself is generic.
(Aside: note that you have no formal restriction for T to be only Double or Int. For example, let event = Event(time: Date(), value: EventValue(value: "123abc")) is possible as well. If you do want to strictly avoid that, Martin R's answer gives one solution.)
*Without getting into too much detail, it's more like a "thing that creates a type" than a type itself.
If the intention is to have a (single) Event type with an EventValue property which can hold either an integer or a double value, then an enum with associated values would serve that purpose:
enum EventValue {
case ival(Int)
case dval(Double)
}
struct Event {
let time: Date
let value: EventValue
}
let event1 = Event(time: Date(), value: .dval(40.3467))
let event2 = Event(time: Date(), value: .ival(1234))