For example, this works:
var x: Int? = 3
I know that optionals are just an enum with an associated value so I was wondering if this is something that is achievable by normals users or if this is compiler magic.
For example, this works:
var x: Int? = 3
I know that optionals are just an enum with an associated value so I was wondering if this is something that is achievable by normals users or if this is compiler magic.
It's compiler magic, non-optional values can be automatically promoted to optionals in certain contexts.
You can narrowly achieve the same thing for literals (like nil, 123, 123.45, true, "string", ["array"], ["dict": 123], etc,) using the ExpresisbleByXLiteral protocols.
Swift doesn't have anything like C#'s user defined conversion operators that would allow you to implement implicit conversion like this in the general case (for non-literal values).
I have mixed feelings. There are certainly times when they're really cool and clean up noisy code. But it also makes it harder to read code if you're not super attentive and don't have access to an IDE to assist your navigation (e.g. you're reading code on GitHub in your browser).
It is not only about conversion operator. Swift compiler treat T as a subtype of Optional<T>.
Unfortunately it seems there is no way to do the same trick for custom types.
enum CopyingChoice<NewValue> {
case copyFromSource
case new(NewValue)
case removeCurrent
}
struct Foo {
// properties ...
func copy(name: CopyingChoice<String> = .copyFromSource,
price: CopyingChoice<Double> = .copyFromSource) -> Self {
...
}
}
What I want is: product.copy(price: 99.9) // 99.9 can not be assigned to argument of type CopyingChoice<Double>
So the only way is: product.copy(price: .new(99.9))
It will be very good to have a feature for explaining compiler how to init such types from their Wrapped types.
It will be useful for not only enums, but for structs too (if they have special initializers in a manner of ExpressibleBy protocols family).
Another direction is Optional-like syntax for other types like Result, Either and others:
var optional: Int?
optional = nil // we don't write .none here
optional = 5 // we don't write .some(5) here
So this way it should be nice to write:
var result: Result<Int, DecodingError>
result = 5 // instead of result = .success(5)
result = DecodingError() // instead of result = .failure(DecodingError())
Of course there should be reasonable limitations to avoid pitfalls. As an example, this should be prohibited:
public enum Either<L, R> {
case left(L)
case right(R)
}
var foo: OneOf2<String, any CustomStringConvertible>
foo = 5 // ok, here it is clear that is .second(5)
foo = "Hello" // can be assigned to both cases, no way to choose one
// even worse if `String` type for .left will be change to `any CustomStringConvertible` later
This we could do today by adopting ExpressibleByNilLiteral.
For this we'd need something like:
protocol ExpressibleByWrappedValue {
associatedtype Wrapped
init(_ wrapped: Wrapped)
}
Until then consider some ad-hoc workaround:
enum MyOptional<Wrapped> {
case none
case some(Wrapped)
}
prefix operator £
prefix func £<Wrapped>(_ wrapped: Wrapped) -> MyOptional<Wrapped> {
.some(wrapped)
}
var value = 42
var opt: MyOptional<Int> = £value
I often experiment with such things but then realise the total saving is not significant, YMMV.