Null-coalescing assignment operator in Swift 3 - swift

I'm trying to create a null-coalescing assignment operator in Swift 3. In other words, instead of this:
x = x ?? y
I want this:
x ??= y
Swift 3 does not seem to like my operator. Here's its definition:
infix operator ??= : AssignmentPrecedence
func ??=(lhs: inout Any?, rhs: #autoclosure () -> Any?) {
if lhs != nil { return }
lhs = rhs()
}
var x = 3
x ??= 7 // Cannot convert value of type 'Int' to expected argument type 'inout Any?'.
I've done it without the #autoclosure too. My understanding is that the precedence group AssignmentPrecedence already contains the assignment declaration, so this is unlikely to be the problem.
How can I do this in Swift 3?

First, make the operator generic instead of using Any:
infix operator ??= : AssignmentPrecedence
func ??=<T>(lhs: inout T?, rhs: #autoclosure () -> T?) {
if lhs != nil { return }
lhs = rhs()
}
Second, the left operand needs to be an optional (otherwise it
could not be tested against nil):
var x: Int? = 3
x ??= 7

I came up with my own 'flavor' of a null-coalescing assignment operator, similar to the above, but by adding a return type, you can both do assignment and return at the same time which is more in line with normal '??' behavior, with the addition of the assignment from the RHS to the LHS if LHS is null. It's perfect for resettable lazy vars. Here's my version...
// Null-coalescing assignment operator
infix operator ??= : AssignmentPrecedence
#discardableResult
func ??= <T>(lhs:inout T?, rhs:#autoclosure () -> T) -> T {
if let lhs = lhs {
return lhs
}
let rhsResult = rhs()
lhs = rhsResult
return rhsResult
}
With the above, I can now do resettable lazy vars like this...
private var qCache:Int?
var q:Int {
return qCache ??= {
print("Lazy-calculating q...")
return 44
}()
}
func resetQ() { qCache = nil }
print("1: q is \(q)")
print("2: q is \(q)")
print("3: q is \(q)")
print("Resetting lazy q...")
resetQ()
print("4: q is \(q)")
Output...
Lazy-calculating q...
1: q is 44
2: q is 44
3: q is 44
Resetting lazy q...
Lazy-calculating q...
4: q is 44
You can also implement the setter too, if you wish as well as separating out the 'lazy calc' function...
func lazyCalcQ() -> Int {
print("Lazy-calculating q...")
return 44
}
private var qCache:Int?
var q:Int {
get { return qCache ??= lazyCalcQ() }
set { qCache = newValue }
}
func resetQ() { qCache = nil }
Going a step further, you can use implicitly-unwrapped datatypes so you can use the assignment of nil to be the reset, yet you are always guaranteed a value from the getter. The only down-side is you still sometimes have to force-unwrap it to silence some warnings like in the print statements below, but again, you are guaranteed a value, so it's safe to do.
Note: Personally I prefer the approach above with the non-implicitly-unwrapped version and the extra 'reset' function--especially if it's a read-only property--because it makes the API much clearer, but I'm sharing this for completeness since it shows a creative use for nil-as-reset.
func lazyCalcR() -> Int {
print("Lazy-calculating r (i.e. the default when reset with 'nil')...")
return 10
}
private var rCache:Int?
var r:Int! {
get { return rCache ??= lazyCalcR() }
set { rCache = newValue }
}
print("1: r is \(r!)")
r += 10
print("2: r is \(r!)")
r += 10
print("3: r is \(r!)")
print("Resetting r to default...")
r = nil
print("4: r is \(r!)")
Output...
Lazy-calculating r (i.e. the default when reset with 'nil')...
1: r is 10
2: r is 20
3: r is 30
Resetting r to default...
Lazy-calculating r (i.e. the default when reset with 'nil')...
4: r is 10
Of course the above are all trivial examples using an int, but I use it to do things like calculating complex paths based on bounds, etc.
My next attempt will be to hide all of this in property wrappers, eliminating the need for this operator itself.

Related

Swift define and call inline closure directly

I can assign an inline closure to a function type
> var a = { ()-> Bool in return true }
and use it:
> true==a()
$R2: Bool = true
if the function is a throw-away, it would be nice to use an inline directly. This doesn't work:
> true=={ ()-> Bool in return true }
error: repl.swift:16:5: error: binary operator '==' cannot be applied to operands of type 'Bool' and '() -> Bool'
According to the error, the RHS is the inline's function type, not its return type. Is there a different syntax I should use? Is it possible to call an inline directly?
Edit, after answer: This comes in very handy in cascaded conditions in if statements: if b==2, { /* do something only if b==2 passes*/}(), let x = ... { ...} else {...}
> true == a()
compares true with the result of calling the closure a (with an empty argument list). You can do the same inline, but you must still call the closure:
> true == { ()-> Bool in return true }()
$R0: Bool = true
Note that a test for equality with true is always redundant, so this expression is identical to
{ ()-> Bool in return true }()

How to extend String.Iterator in Swift

I have a String like LINNIIBDDDN, basically a series of tokens. I'd like to use multiple iterators, one for each token type. I'd like to have each iterator ignore the tokens that don't belong to it. That is, I want to call something like next_ish(), to advance the iterator to the next element of its particular token. So if the Niterator is at index 3, and I call next_ish(), I want it to go to index 10, the next N, not the I at index 4. I have some code that already works, but it's a lot of code, it makes the String into an array, and I have subclassed iterators, basically hand-written, with no help from Swift, although I'm sure the Swift iterators are more stable and thoroughly tested. I'd rather use their code than mine, where possible.
It seems like it should be easy just to extend String.Iterator and add next_ish(), but I'm at a loss. My first naive attempt was to extend String.Iterator. I get the error Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause. I went looking to figure out what kind of where clause to use, and I haven't found anything.
There are a lot of answers here on SO, about extending arrays and generics, pulling all the elements of a certain type into an array of their own, even some answers about specialized for...in loops, but I can't find anything about extending iterators. I've read through Collections.swift and haven't found anything helpful. Is it possible to extend String.Iterator? That would make my life a lot easier. If not, is there some sort of built-in Swift mechanism for doing this sort of thing?
String.Iterator is (implicitly) defined as
typealias Iterator = IndexingIterator<String>
and the error message
Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause
means that we must define extension methods as
extension IndexingIterator where Elements == String { }
Alternatively (with increasing generality):
extension IndexingIterator where Elements: StringProtocol { }
extension IndexingIterator where Elements.Element == Character { }
I haven't found a way to access the underlying collection (or position)
from within an extension method, the corresponding members are defined as
“internal”:
public struct IndexingIterator<Elements : Collection> {
internal let _elements: Elements
internal var _position: Elements.Index
// ...
}
What you can do is to pass the wanted element to your “next-ish” method,
either as the element itself, or as a predicate:
extension IndexingIterator where Elements.Element == Character {
mutating func next(_ wanted: Character) -> Character? {
while let c = next() {
if c == wanted { return c }
}
return nil
}
mutating func next(where predicate: ((Character) -> Bool)) -> Character? {
while let c = next() {
if predicate(c) { return c }
}
return nil
}
}
Example usage:
var it1 = "ABCDABCE".makeIterator()
print(it1.next("C") as Any) // Optional("C")
print(it1.next() as Any) // Optional("D")
print(it1.next("C") as Any) // Optional("C")
print(it1.next() as Any) // Optional("E")
print(it1.next("C") as Any) // nil
var it2 = "LINnIIBDDDN".makeIterator()
while let c = it2.next(where: { "Nn".contains($0) }) {
print(c, terminator: ", ")
}
print()
// N, n, N,
But actually I would consider String.Iterator being an IndexingIterator an implementation detail, and extend the IteratorProtocol instead:
extension IteratorProtocol where Element: Equatable {
mutating func next(_ wanted: Element) -> Element? {
while let e = next() {
if e == wanted { return e }
}
return nil
}
}
extension IteratorProtocol {
mutating func next(where predicate: ((Element) -> Bool)) -> Element? {
while let e = next() {
if predicate(e) { return e }
}
return nil
}
}
That makes it usable for arbitrary sequences. Example:
var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
while let e = it3.next(where: { $0 % 2 == 0} ) {
print(e, terminator: ", ")
}
print()
// 2, 8, 34,

Using "!" on contains

Given this code:
let a = [1, 2, 3, 4, 5]
let b = [5, 6, 7, 8, 9]
let result = a.filter(b.contains)
print(result) // [5]
But what if I want let result = a.filter { !b.contains($0) }? How can I do it the same way as the example above?
let result = a.filter { !b.contains($0) } // works
let result = a.filter(!b.contains) // fails
let result = a.filter { !b.contains($0) }
This is syntactic sugar for:
let result = a.filter({ !b.contains($0) })
filter takes a function value. {...} is a literal function value (a "closure"), just like 1 is a literal Int value. So that's fine. Inside the closure, you apply the ! prefix operator to the result of b.contains($0). That's also fine.
let result = a.filter(!b.contains) // fails
Again, filter takes a function value. b.contains is a function value, so that part is fine, which is why a.filter(b.contains) works. But the ! prefix operator can't be applied to a function value, so that fails.
Anurag demonstrates how you would write an implementation of ! that does take a function and return a function, which works, but would be confusing IMO because this is not a standard use of that operator, and these kinds of operator overloads tend to slow down the compiler (sometimes dramatically, because it has to chase more type possibilities). While there are various ways you might try to "make this work," the best Swift here would generally be the closure syntax because it's clear and standard.
That said, a reasonable approach if you were doing this kind of thing a lot, would be to create a not function that takes a function and returns a function, like Anurag's !, but without overloading the operator:
func not<T>(_ predicate: #escaping (T) -> Bool) -> (T) -> Bool {
return { !predicate($0) }
}
Then you could call a.filter(not(b.contains)). But again, I'd probably only do that if building up complex functions were an important part of your program.
You can always create a custom operator.
prefix func !<T>(_ predicate: #escaping (T) -> Bool) -> (T) -> Bool {
return { element in
return !predicate(element)
}
}
and then a.filter(!b.contains) will work.
Or if that feels like operator overloading abuse, then you could just extend Sequence and use it as a.filter(b.not(b.contains)) but it's kind of ugly:
extension Sequence {
func not(_ predicate: #escaping (Self.Iterator.Element) -> Bool) -> (Self.Iterator.Element) -> Bool {
return { element in
return !predicate(element)
}
}
}

Swift closure capture and inout variables

Consider the following code:
func foo(inout success: Bool) -> (()->()) {
return { _ in
success = true
print (success)
}
}
var success = false
let closure = foo(&success)
closure() //prints "true"
print(success) //prints "false"
The closure appears to be creating a copy of success and does not change the original. Why is this taking place? I had assumed that the closure would point to the original because we are passing an inout variable.
It makes sense that this wouldn't update your success variable because your inout parameter is a parameter of foo, not of the closure itself. You get the desired behavior if you make the inout parameter a parameter of the closure:
var success = false
let closure = { (inout flag: Bool) -> () in
flag = true
print(flag)
}
closure(&success) //prints "true"
print(success) //prints "true"
This pattern also works with the function, too, as long as you keep the inout parameter a parameter of the closure:
func foo() -> ((inout Bool)->()) {
return { flag in
flag = true
print (flag)
}
}
var success = false
let closure = foo()
closure(&success) //prints "true"
print(success) //prints "true"
You also get the desired behavior if you use a reference type:
class BooleanClass: CustomStringConvertible {
var value: Bool
init(value: Bool) {
self.value = value
}
var description: String { return "\(value)" }
}
func foo(flag: BooleanClass) -> (()->()) {
return {
flag.value = true
print (flag)
}
}
let success = BooleanClass(value: false)
let closure = foo(success)
closure() //prints "true"
print(success) //prints "true"
This seems to be covered by Swift Evolution proposal 0035, and is considered a bug.
The document there refers to the inout parameter to the function as "a shadow copy that is written back to the argument when the callee returns". This seems to mean that there is, in essence, a temporary variable named success in the executing context of foo(). The value of that temp is then put into the outer success only when foo() returns.
Since in your foo(), the closure has not run when foo() returns, the value of the "shadow copy" has not changed. The outer success keeps its value.
The important part is that the closure has captured the shadow copy, not the outer success as you expect. So when the closure finally runs, that variable's value does change, but it no longer has any connection to the original outer success.
The proposal uses this snippet to demonstrate:
func captureAndEscape(inout x: Int) -> () -> Void {
let closure = { x += 1 }
closure()
return closure
}
var x = 22
let closure = captureAndEscape(&x)
print(x) // => 23
closure()
print("still \(x)") // => still 23

Need help in using Swift inout with optional

This is the function I tried to use
func merge(inout A: DNode?, inout And B: DNode?) -> DNode? {
if A == nil && B == nil {
return nil
}
if A == nil {
return B
}
if B == nil {
return A
}
return A!.isLessThan(B!) ? A! : B!
}
Here is how I tried to use the function 'merge'
class Heap {
var minDNode: DNode?
func start(inout newNode: DNode) {
self.minDNode = merge(&self.minDNode, And: &newNode) // error
// Cannot invoke 'merge' with an argument list of type '(inout DNode?, And: inout DNode)'
}
func merge(inout A: DNode?, inout And B: DNode?) -> DNode? {
...
}
}
How can I fix the problem?
Looking at the answer from Swift optional inout parameters and nil,
making
var minDNode: DNode?
into
var minDNode: DNode? = nil
didn't solve the problem
#MartinR makes a good point in the comments: "Why does merge() take inout parameters? The arguments are not modified, so this seems like an unnecessary complication."
The reason for the error is that you have to pass the exact type when using inout, and DNode and DNode? are two different types.
newNode needs to be declared as optional because that is what merge is expecting:
func start(inout newNode: DNode?) {
self.minDNode = merge(&self.minDNode, And: &newNode) // this call now works
}
You probably should rework your code, though, to remove the inout calls where they aren't needed.