Does Swift have something like "ref" keyword that forces parameter to be passed by reference? - pass-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.

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)

Inout in swift and reference type

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.

Annotating the whole of a function declaration with a typealias

My goal is to use a typealias as a one-word reminder “attached” to a function declaration. Say,
typealias VoidToVoid = () -> ()
I can use the type alias when stating the expected type of a closure, thus
let f : VoidToVoid = { return }
assert(f is VoidToVoid)
However, this does not seem the most usual way of declaring functions. I was hoping for a way to tell the reader that a function declared like f′ below, should be of type VoidToVoid, and using that name.
(But without the reader having to infer, or to think, or to wait for the compiler to tell him or her about the type. Aggravating the situation, the compiler cannot know the type alias name I had wanted with f′ and will likely output messages stating the bare type, not the alias.)
func f′() : VoidToVoid { // tentative syntax
return
}
Can I get there at all?
Edit: There are two ends at which the type alias is to be used. At one end, this is now possible:
func giveMeAClosure(_ f: VoidToVoid) {
f()
}
At the other end, being VoidToVoid is implicit:
func canBeGivenAsClosure() {
// ...
}
That is, where canBeGivenAsClosure is declared, it is true but not obvious that there is a connection between the two ends through VoidToVoid. This is different from the let case, which can have "VoidToVoid" as its type annotation.
Closures are unnamed closure expressions, which is why we may use a function type typealias to specify the type of the closure, even for closures that have a non-empty argument list.
typealias VoidToVoid = () -> ()
typealias IntToVoid = (Int) -> ()
// unnamed closure expressions
let f: VoidToVoid = { print("foo") }
let g: IntToVoid = { print($0) }
Note here that f and g in these exaples are not functions: they are simply immutable properties that holds references to (the backing storage of) the unnamed closures specified at the time of their declaration.
A function, one the other hand, is a special case of a closure; a closure with a name. Moreover, any function with a non-empty argument list needs to supply in internal (and optionally) and external parameter names in its declaration. A function type typealias, however, may not contain argument labels for its parameter names:
typealias IntToVoid = (a: Int) -> ()
/* Error: function types cannot have argument
label 'a'; use '_' instead */
This means that a function type typealias can't possible be used a substitute for the combined parameter and return type declaration part of a function (not even in the () -> () case).
For details, see e.g.:
The Language Guide - Closures
Closures
...
Global and nested functions, as introduced in Functions, are actually
special cases of closures. Closures take one of three forms:
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
On another note, you may naturally test the type of a given function to some existing function type typealias.
typealias VoidToVoid = () -> ()
typealias IntToVoid = (Int) -> ()
func f() -> () {}
func g(_ a: Int) -> () { _ = a }
print(f is VoidToVoid) // true
print(g is IntToVoid) // true

Swift 3.0 closure expression: what if the variadic parameters not at the last place in the parameters list?

Update at 2016.09.19
There is a tricky, indirect way to use variadic parameters before some other parameters in closure expression parameters list, haha
let testClosure = { (scores: Int...) -> (_ name: String) -> String in
return { name in
return "Happy"
}
}
let k = testClosure(1, 2, 3)("John")
And I found some related issues in bugs.swift.org:
SR-2475
SR-494
Original Post
According to the document of Swift 3.0, for a closure expression, "variadic parameters can be used if you name the variadic parameter"(see Closure Expresssion Syntax part). But for Swift 2.x, the description is "Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list", the border part has been removed in Swift 3.0 document, is it means variadic parameter can be a argument of closure expression even it is not at the last place? If so, why the codes below can't compile successfully?
let testClosure = { (scores: Int..., name: String) -> String in
return "Happy"
}
let k = testClosure(1, 2, 3, "John") // Missing argument for parameter #2 in call
If the argument label can be used in the call, I think the compiler can compile the code above successfully, but in Swift 3.0, closure expression's argument labels are regarded as Extraneous.
Besides, Swift 3.0 document indicates that the parameters in closure expression syntax can be in-out parameters, but Swift 3.0 said that closure expression syntax can use constant parameters, variable parameters, and inout parameters. Why Apple removed descriptions like constant parameters, variable paramters, is it because in Swift 3.0, the parameters can't be var?
Thank you very much for your help!
Still in Swift3 variadic arguments have to be the last parameter in the signature, because despite the fact that in your case the last parameter typed as String can be deduced, there's some cases where not, because of the infinite expansion of variadic argument:
let foo = { (i:Int..., j: Int) -> Int in
return j
}
foo(1,2)
...in Swift 3.0, the parameters can't be var?
var params where removed in Swift3 SE-0003 to avoid confusion with inout parameters, because both var and inout params can be assigned inside function, but just inout is reflected back.
func doSomethingWithVar(var i: Int) {
i = 2 // change visible inside function.
}
func doSomethingWithInout(inout i: Int) {
i = 2 // change reflected back to caller.
}
removing var from parameter list, remove the confusion above.
Variadic parameter have to be last and according to your situation, you can type this:
let testClosure = { (_ name: String, scores: Int...) -> String in
return "Happy"
}
let k = testClosure("John", 1, 2, 3)
You are able to create a func in Swift 3.0 where the variadic parameter is NOT the last argument. For example...
func addButtons(buttons: UIButton..., completion: (() -> ())? = nil)
I believe it's because the parameter following the variadic parameter is named, and so the func does not confuse the next named argument with more variadic arguments.
addButtons(buttons: button1, button2, button3) {
//do completion stuff
}

Add default value to inout parameter using Swfit

In Swift 2 it is possible to do the following:
class SomeType {
static let singletonInstance = SomeType()
func someFunction(var mutableParameter: SomeType = SomeType.singletonInstance) {
...
}
}
However in Swift 3 the var keyword will be removed for function parameters in favour of inout. I have not been able to achieve the same result as the above using the inout keyword.
class SomeType {
static let singletonInstance = SomeType()
func someFunction(inout mutableParameter: SomeType = SomeType.singletonInstance) {
...
}
}
Instead I receive an error of "Default argument value of type 'SomeType' cannot be converted to type 'inout SomeType'"
My question is whether it is possible to use inout with default value?
The two keywords you're talking about, inout and var, are very different.
From Apple Documentation:
In-out parameters are passed as follows:
When the function is called, the value of the argument is copied.
In the body of the function, the copy is modified.
When the function returns, the copy’s value is assigned to the original argument.
Therefore you can't give a default value to an inout parameter, as it would make the inout property completely useless.
What you can do is receive a normal (constant) parameter with a default value, and declare a new var with the same name this way (code from the Swift Evolution's Removing var from Function Parameters Proposal, with the addition of the default parameter):
func foo(i: Int = 5) {
var i = i
// now you can change i as you'd like
}
Anyone who needs a default inout parameter may consider such solution:
class SomeType {
static let singletonInstance = SomeType()
func someFunction(inout mutableParameter: SomeType) {
...
}
// Declare function without 'mutableParameter':
func someFunction() {
someFunction(SomeType.singletonInstance)
}
}
When you specify the default value for the parameter, the Swift compiler automatically generates a function without the parameter, for you. In this solution we do it manually.
You could create a second function signature to "emulate" a default value
func foo() {
var v: Int = 0 // your default value
foo(bar: &v)
}
func foo(bar: inout Int) {
// do stuff
}