Inout in swift and reference type - swift

I'm trying to understand the difference between value and reference type. And now I want to use function from the apple guide:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
and if I want to use this is function I will write this code
swapTwoInts{&firstIntStruct, &secondIntStruct}
I understand that we must put in this function reference type, but Int is a value type, therefore we use &.
In another hand, when I try change Int to my class in the swap function, I also must write & before instance of my class.
Why I must do it, if it is the reference already?

Suppose we wrote the hypothetical function you're talking about:
class C {}
func swapTwoC(_ lhs: C, rhs: C) {
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
The immediate problem is that lhs and rhs are immutable. To mutate them, we would need to make mutable copies:
func swapTwoC(_ lhs: C, rhs: C) {
var lhs = lhs; var rhs = rhs
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
But now the problem is that we're mutating our copies, and not the original references our caller gave us.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
When you have an inout C, and you pass in &myObject, what you're actually passing in is a reference to your reference to myObject. When the function arguments are copied, what's copied is this "ref to a ref". The function can then use that "ref to a ref" to assign a new value to the reference myObject the caller has

I would like to explain it with example. As #Alexander mentioned, for th function with Int as parameter:
1. Pass by value
It will mutate the copies, and not the original references of caller.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
You can see that
func swapTwoInts(_ a: Int, _ b: Int) { }
If has changed the values of p and q, where self.x and self.y are unchanged. As this function is passing the values of x and y not their reference.
2. Pass by reference:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { }
It passes the reference of self.x and self.y and that's why you don't have to mutate them again as you did by taking p and q in previous type. Because it will take mutating object with var x and var y.
You can see that, a and b have values of references in logs and changing a and b has changed the self.x and self.y as well because a and b has the same reference( address) of x and y.

So there a few lower level memory components that are at play to make full sense of this.
1) When you create a value or reference type you have a new variable on the stack. That variable is either the actual data in the case of a value type or a pointer to the data in the case of a reference type.
2) When you call a function, it creates a new part of the stack and it creates new variables on the stack (which are let instances in swift) that copy the variable passed in. So for value types it does a deep copy and for reference types it copies the pointer.
So what this means is that when you use inout you are saying, take the memory address of this variable and update the data it contains. So you can either give a value type new data or a reference type a new pointer address and it will change outside of the scope of the swap function. It makes it a var (the same one as what is passed in) instead of let like normal.

Related

Swift Passing a member function to a function that takes an optional closure

I'm trying to construct a table that contains, among other things, an optional closure. When I try to instantiate an instance of the table, passing a member function for the closure I get a compile error.
From the error msg it appears that a member function can not be converted to an optional member function. I don't see why not; an Int or other types can easily be converted to optionals.
struct Foo {
typealias Routine = (_ x: Int) -> Int
let int: Int
let aRoutine: Routine?
init(_ int: Int, _ routine: Routine? = nil) {
self.int = int
self.aRoutine = routine
}
}
class Bar {
let foo = Foo(5, doSomething) // Compile error here
func doSomething(_ x: Int) -> Int {
return x
}
}
Cannot convert value of type '(Bar) -> (Int) -> Int' to expected argument type 'Foo.Routine?' (aka 'Optional<(Int) -> Int>')
You've just discovered that member functions (a.k.a. instance methods) are curried in Swift. See Instance Methods are “Curried” Functions in Swift
Foo.doSomething(_:) isn't just a free function (a.k.a. global function). It's an instance method that has access to the instance, self. But if you just take the method as a closure directly, it doesn't know what the value of self would be.
There are several options:
If your implementation of doSomething(_:) doesn't need to access self, then you can move it out of the Foo's declaration, and declare it as a global function.
Alternatively, you can turn it into a static function by keeping it where it is and using the static modifier. This has an added benefit over a global function, in that it "organizes" your code by moving it into an appropriate namespace.
If your implementation of doSomething(_:) does need an instance to operate on, then you can access the unapplied method of that instance. Here's an example. I've added explicit type annotations for demonstration, but you should usually omit those.
let object: Bar = Bar() // an object of type Bar
let boundDoSomethingMethod: (Int) -> Int = object.doSomething // a bound method which operates on `object`
// alternatively:
let unboundDoSomethingMethod: (Bar) -> (Int) -> Int = Bar.doSomething
let boundDoSomethingMethod: (Int) -> Int = unboundDoSomethingMethod(object)

How to express the type of a constrained-generic function in Swift?

I can define a function
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
Now I want to type a variable to hold exactly this kind of function, but I find I can't spell the type:
let f: (SomeProtocol) -> SomeProtocol // doesn't express the genericity
let f: <A: SomeProtocol>(A) -> A // non-existent syntax
Is there any way I can express this directly?
Note that in particular I want f to still be generic: it should accept any SomeProtocol conformer (so no fixing the generic type parameter in advance). In other words: anything I can do with myGenericFunc I want to also be able to do with f.
The quick answer is no, you can't use a single variable to hold different function implementations. A variable needs to hold something concrete for the compiler to allocate the proper memory layout, and it can't do it with a generic construct.
If you need to hold different closure references, you can use a generic type alias:
typealias MyGenericFunction<T: SomeProtocol> = (T) -> T
var f1: MyGenericFunction<SomeConformerType> // expanded to (SomeConformerType) -> SomeConformerType
var f2: MyGenericFunction<AnotherConformerType> // expanded to (AnotherConformerType) -> AnotherConformerType
My original question was about expressing the type directly, but it's also interesting to notice that this is impossible for a different reason:
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
let f = myGenericFunc // error: generic parameter 'A' could not be inferred
You could see this as the "deeper reason" there's no spelling for the generic type I wanted: a variable (as opposed to a function) simply cannot be generic in that sense.

Declare overloaded += operator as mutating?

I am overloading (or maybe implementing in this case) the += operator for a class (not a struct!). The operation modifies the state of the left-hand-side instance. I noticed that I can declare the left-hand-side element with let without any errors (and since it is an instance of a class, it's internal state changes with the operation). This of course is undesired, and should result in a compile-time-error. Is there a way to declare the overloaded operator as mutating to the left-hand-side element?
class MyClass {
static func +=(lhs: MyClass, rhs: MyClass) {
lhs.fu(rhs) // fu() changes internal state of lhs
}
}
let a = MyClass()
let b = MyClass()
a += b // this is legal but shouldn't be, since instance 'a' will
// have a different internal state after the concatenation
The let constant in this case is the reference a to the MyClass object that it points to. It prevents you from being able to do this:
let a = MyClass()
a = MyClass() //redefinition not allowed
It does not guarantee anything about the constancy of the members of that object however. Classes/objects exist to model constantly changing data, marking methods as mutating would be a bit tedious, because ultimately that's what they're supposed to do, in general.
You should be using structs in cases where you want controlled mutation.

Closure closing strongly over a class type instance that go out of scope; can the instance be accessed somehow via the closure instance?

Question: For the case of ()-return closures, is there any way to access a variable that ARC lets live only due to a single strong reference from a closure closing over it? In the example below: accessing bb in the closure.
Below follows an example to show what I mean.
In the Language Reference - Expressions, it reads
Capture Lists
By default, a closure expression captures constants and variables from
its surrounding scope with strong references to those values. You can
use a capture list to explicitly control how values are captured in a
closure.
...
Consider the following example, using a weak and a strong capture of two class type instances
class MyClass {
var myInt : Int = 0
func printMyInt() {
print(myInt)
}
}
func getClosure(a: MyClass, _ b: MyClass) -> (() -> ()) {
return { [weak aa = a, bb = b] in
aa?.printMyInt() ?? print("Lost reference")
bb.printMyInt()
}
}
func foo() -> (() -> ()) {
let a = MyClass()
let b = MyClass()
let closure = getClosure(a, b)
closure() // 0, 0
a.myInt = 1
b.myInt = 2
closure() // 1, 2
return closure
}
If foo() is called, then at the return of closure, MyClass instances a and b are out of scope. In the closure itself, aa keeps a weak reference to a, so a (memory) will be "destroyed" by ARC, and aa will become nil.
However, since the closure closes over b with a strong reference, ARC will retain the memory for b until the closure itself goes out of scope.
let closure = foo()
closure() // Lost reference, 2 <-- OK, expected
/* 'b' (not the reference, but the object in memory) still lives, but
cant be explicitly accessed? */
Hence my question: how to access, in this case, bb within the closure.
What I've tried
I've tried without success using Mirror:
var bar = Mirror(reflecting: closure)
print(bar.children.count) // 0
Also, I know we can "access" bb in the example above by adding a return type (MyClass) to the closure, but I'm wondering if we can actually access it without such a workaround (hence the ()-return specific closure in the question above).
Where I've looked prior to posting this question
I've been searching around SO for a possible existing threads that asks and answers this question, but the closest one I found,
Getting data out of a closure in swift,
don't really answer my question here. (Or perhaps the workarounds in the answers to that question does, and the answer to my question above is "you can't"?)

Does Swift have something like "ref" keyword that forces parameter to be passed by reference?

In Swift, structs and value types are passed by value by default, just like in C#. But C# also has a very usable ref keyword, that forces the parameter to be passed by reference, so that the same instance could be changed inside the function and accessed from the caller's scope afterwards. Is there a way to achieve the same result in Swift?
Use the inout qualifier for a function parameter.
func swapTwoInts(a: inout Int, b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoInts(&someInt, &anotherInt)
See Function Parameters and Return Values in the docs.