Swift: Assigning Function to Variable

Swift: assigning function to variable

The postfix .self expression just refers to the object it's an instance of. Kind of like .this in other languages. For types in particular, it tells the compiler that you're referring to the type itself, rather than instructing it to create a new instance of that type. If you'd like to know more, you can read all about it in the docs here. While useful in a lot of cases, it's not really needed here.

As for your problem, when you assign:

var pendingFunction = ((Double, Double) -> Double).self

You're assigning the type of a particular sort of function as the value of the variable. From that, Swift infers that the type of the variable should be Type. Then later when you try to assign an actual function fitting that type as the value, it throws an error because it's expecting a type, not a function.

Instead of assigning a type as value, you want to declare the variable with that type as its type:

var pendingFunction: ((Double, Double) -> Double)

Here's an example of the whole thing:

var pendingFunction: ((Double, Double) -> Double)

func myAdditionFunction (first: Double, second: Double) -> Double {
return first + second
}

pendingFunction = myAdditionFunction

print(pendingFunction(1,2)) // prints "3.0"

Assigning function to a variable in swift strange behavior

This appears to be a bug in the playground. It works in a project without trouble.

It can be simplified, though (I realize this probably isn't your real code, but it offers a good example of better approaches):

func swapper(inout arr: [Int]){
(arr[0], arr[arr.count - 1]) = (arr[arr.count - 1], arr[0])
}

//let myFunctionPointer : (inout [Int])->Void = swapper
let myFunctionPointer = swapper // There's no real reason for a type here

var x = [1,2,3]
myFunctionPointer(&x)
println(x)

Note that putting arr at the end of your function is not a good practice. Swift does not return the last value computed, so this line does nothing at all (but create some confusion).


EDIT: Actually, it can be even a little simpler than that (I didn't realize this would work until I tried it):

func swapper(inout arr: [Int]){
swap(&arr[0], &arr[arr.count-1])
}

How To Store Swift function in a variable

You have to help the compiler decide which function you want because it does not distinguish between parameter names when deciding if a function's signature is valid for assignment.

You can disambiguate your intent by being specific on the parameter names

let c:  (left :String) -> () = cars(left:)
let c2: (right:String) -> () = cars(right:)

Assign method (function of an object) to a variable or how to pass a parameter to unit tests

It turns out that for each instance method a type has, there's a
corresponding static method that lets you retrieve that instance
method as a closure, by passing an instance as an argument.

For example: [3, 2, 1].sort() == Array.sort([3, 2, 1])

Interesting fact, but pretty useless in our case, because

Partial application of 'mutating' method is not allowed.

So as long as I can't pass a mutating method as a parameter, I will pass an enumeration object:

extension Array where Element == Int {

mutating func sort(_ algorithm: SortAlgorithm) {
switch algorithm {
case .bubble: bubbleSort()
case .selection: selectionSort()
}
}
}

enum SortAlgorithm {
case bubble
case selection
}

As for second part of the question I think the best answer is inheritance:

// MARK: - Basic UnitTest Class

class SortingTest: XCTestCase {
static var algorithm: SortAlgorithm!

override static func tearDown() {
algorithm = nil
super.tearDown()
}

func testSorting1() {
var a = [9, 2, 5, 3, 8, 1, 4, 7, 6]
a.sort(Self.algorithm)
XCTAssertEqual(a, [1, 2, 3, 4, 5, 6, 7, 8, 9])
}

func testSorting2() {
var a = [4, 3, 2, 1]
a.sort(Self.algorithm)
XCTAssertEqual(a, [1, 2, 3, 4])
}
......

// MARK: - Inherited UnitTest Classes

class BubbleTest: SortingTest {

override static func setUp() {
super.setUp()
algorithm = .bubble
}
}

class SelectionTest: SortingTest {

override static func setUp() {
super.setUp()
algorithm = .selection
}
}

Everything is ready for nicely calling tests for appropriate sorting algorithm:

extension enum SortAlgorithm {

func runTests() {
switch self {
case .bubble: BubbleTest.defaultTestSuite.run()
case .selection: SelectionTest.defaultTestSuite.run()
}
}
}

SortAlgorithm.bubble.runTests()

P.S. Thank @DávidPásztor and @matt for hints :)

Assign print function to a variable

I believe you've found a known bug (or limitation) of the Swift compiler.

The built-in print function has three parameters. Parameter #1 is unlabeled and is type String ... (variadic). Parameter #2 has label separator, is type String, and has a default value. Parameter #3 has label terminator, is type String, and has a default value. Since parameters #2 and #3 have default values, you can call it like print("hello").

Closures (like myPrint) cannot use labeled parameters. So myPrint takes three unlabeled parameters. Parameter #1 is type String ... (variadic). Parameter #2 is type String. Parameter #3 is also type String. Closure parameters cannot have default values, so myPrint requires all three parameters. You cannot call it like myPrint("hello"), because you haven't passed anything for parameters #2 and #3 and they do not (and cannot) have default values.

In Swift, a variadic parameter (like parameter #1 of print and myPrint) consumes all arguments until in reaches a label. If you try to call myPrint("hello", " ", "\n"), all three arguments will be assigned to parameter #1, and nothing will be assigned to parameters #2 and #3.

Since you cannot have labeled parameters in a closure, there is no way to call your myPrint closure, because there is no way to pass values for parameters #2 and #3.

This is a known limitation. See SR-2475 and SR-494.

Assign variable to function - Swift 3

Your syntax is a bit mangled.

  • Add underscores to the func signature to improve readability.
  • Pass in a variable only when you want to overwrite the default.
  • Recode this sample func to not always return 1, but return what was passed into it (or the default).

    func foo(_ bar: Int = 10) -> Int {
    return bar
    }

    var demo = foo() // returns the default of 10
    var test = foo(1) // returns the parameter passed in, which is 1

    let result = demo - test

EDIT: The actual question was lost in the errors fixed above. The OP is to have foo(bar:) be a computed property. So the final solution would be:

var _foo:Int = 10
var foo:Int {
get {
return _foo
}
set {
_foo = newValue
}
}

Tested in a viewDidLoad():

print(foo)  // prints 10
foo = 1
print(foo) // prints 1

Please note:

  • You cannot do anything like have a "constant default" to a computed property. Since this is an instance property, you set it once only.
  • You cannot turn a function into a property. Yes, functions are first-class citizens in Swift, but this only means you can "treat them like a variable" by passing them into another function.
  • I tried a few variations (adding "= 10" to the declaration, making the Int an Optional, removing the get from things, and it either doesn't build or crashes.

If you really need to have a default of 10, compute what is passed into things, and have it available globally, I recommend refactoring your concept to use one or the other of these solutions.

Swift function parameters as local variables

Before Swift 3, Swift used to have them. You used to be able to do something like this:

func f(var x: Int) { // note the "var" modifier here
x += 1
print(x) // prints 2
}

var a = 1
f(a)
print(a) // prints 1

But it was removed in Swift 3, via SE-0003. The Swift community decided that this is not a good feature. The motivations given in that proposal are:

  • var is often confused with inout in function parameters.
  • var is often confused to make value types have reference semantics.
  • Function parameters are not refutable patterns like in if-, while-, guard-, for-in-, and case statements.

use variable to store function in swift as pointer function in Obj-C or C++

To solve the error

Class 'MenuScene' has no initializers

you have two options: change the declaration of animationFunction to make it an Optional or create a designated initializer for MenuScene where you assign a value to the non-Optional `animationFunction.

To solve the second error of incompatible types, you need to change the declaration of animationFunction since currently it's type is TimeInterval and not a function type. From the error message it seems you want a function of type (TimeInterval)->(), namely one that accepts a single input parameter of type TimeInterval and returns Void.

To fix both errors, simply modify the declaration of animationFunction to make it Optional and have the required function type:

private var animationFunction: ((TimeInterval)->())?


Related Topics



Leave a reply



Submit