An abbreviation for wrapping a quick variable optionally?

Swift allows you to use the shortened str! notation str! to deploy optional. But what if we want to do the opposite?

Let's say I have a variable:

 var str = String() // String 

Is there a shorthand notation to convert this to optional (i.e. String? Or String! )?

(For example, I want to do something like var strOptional = ?(str) .)

Alternatively, if there are no abbreviations for these notations, how can you convert it to optional without explicitly specifying its type (for example, I do not want to mention String ).

In other words, I know that I can wrap a variable as optional with any of these methods:

 var strOptional = str as String? var strOptional: String? = str var strOptional = String?(str) 

... but in each case I have to explicitly write String .

I would rather write something like: var strOptional = str as typeof?(str) if there is no abbreviated syntax. (The advantage is that if the type of the variable changes frequently in the code base, it will be one less place to update.)


As for the real world, where it would be useful, imagine that I want to use AVCaptureDevice, and I use the following code:

 let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) device.lockForConfiguration(nil) 

lockForConfiguration() will fail during operation on a device that does not have a video camera, and the compiler will not warn me about this. The reason is that defaultDeviceWithMediaType may return nil according to the documentation [1] but it is defined as returning AVCaptureDevice! .

To fix an erroneous API like this, it would be nice to do something like:

 let device = ?(AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)) 

... to get AVCaptureDevice? , and the compiler will catch any errors that I could make.

Currently, I have to resort to a more detailed one:

 let device: AVCaptureDevice? = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) 

Another example:

In this case, I want to specify a default value for my variable, which is a string, but later I can set it to nil .

 var myString = "Hi" // ... if (someCondition()) { myString = nil // Syntax error: myString is String } 

Currently, I have to resort to var myString: String? = "Hi" var myString: String? = "Hi" , but something like var myString = ?("Hi") will be less verbose.


[1] If you open AVCaptureDevice.h, you will see the following documentation about the return value: "The default device with this media type or nil if there is no device with this media type." sub>

+5
source share
3 answers

Optional is just an enumeration in swift, so you can do: Optional(str)

From the quick interface:

 /// A type that can represent either a `Wrapped` value or `nil`, the absence /// of a value. public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible { case None case Some(Wrapped) /// Construct a `nil` instance. public init() /// Construct a non-`nil` instance that stores `some`. public init(_ some: Wrapped) /// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. @warn_unused_result public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U? /// Returns `nil` if `self` is `nil`, `f(self!)` otherwise. @warn_unused_result public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U? /// Create an instance initialized with `nil`. public init(nilLiteral: ()) } 
+2
source

To wrap a variable, you can use operator overloading and general functions. For instance:

 prefix operator ??? {} prefix func ??? <T> (x: T) -> T? { return Optional(x) } 

To associate this with the second example, you should do the following:

 var myString = ???"Hi" // Optional("Hi") if someCondition() { myString = nil } 
0
source

In the light-hearted spirit that, as I understand it, has been asked, you can define a postfix operator that uses one character less than your ideal solution (a pair of pairs and a question mark):

 postfix operator =? {} postfix func =? <T> (rhs: T) -> T? { return rhs } postfix func =? <T> (rhs: T!) -> T? { return rhs ?? nil } var x = 3=? x is Int? //--> true var imp: Int! = 3 var opt = imp=? opt is Int? //--> true 

As for the Apple APIs that you mention, since they already return optional, although implicitly deployed optionally, can you use the nil join operator ?? to convert it to a regular option:

 let y: Int! = 3 // posing for a rogue API y is Int? //--> false let z = y ?? nil z is Int? //--> true 

Perhaps a more interesting use of the tricky operator is a higher-order, higher-order operational function that raises T -> U to T? -> U? T? -> U? s ...

 func opt <T, U> (f: T -> U) -> T? -> U? { // we'll implement this as an operator return { $0.map(f) } } postfix operator ->? {} postfix func ->? <T, U> (f: T -> U) -> T? -> U? { return { $0.map(f) } } 

Now let's use it:

 let square: Int -> Int = { $0 * $0 } let i: Int? = 3 square->? (i) 

Which is equivalent:

 opt(square)(i) 

This is equivalent (but perhaps a little more universal than):

 i.map(square) 

All this makes sense when used with a straight line operator:

 infix operator |> { associativity left precedence 89 } func |> <A, B>(a: A, f: A -> B) -> B { return f(a) } 

Then you can do:

 i |> opt(square) 

or

 i |> square->? 

Or we can combine them into an optional forward channel, which can also take care of implicitly deployed options:

 infix operator ?> { associativity left precedence 89 } func ?> <T, U> (lhs: T?, rhs: T -> U) -> U? { return lhs.map(rhs) } let im: Int! = 5 let op: Int? = 5 im ?> square |> debugPrintln //--> Optional(25) op ?> square |> debugPrintln //--> Optional(25) 

Which is equivalent:

 debugPrintln(op.map(square)) 
0
source

All Articles