In Swift,There's No Way to Get the Returned Function's Argument Names

In Swift,there's no way to get the returned function's argument names?

You're correct. From the Swift 3 release notes:

Argument labels have been removed from Swift function types... Unapplied references to functions or initializers no longer carry argument labels.

Thus, the type of townPlan, i.e. the type returned from calling makeTownGrand, is (Int,Int) -> Int — and carries no external argument label information.

For a full discussion of the rationale, see https://github.com/apple/swift-evolution/blob/545e7bea606f87a7ff4decf656954b0219e037d3/proposals/0111-remove-arg-label-type-significance.md

Swift Closure why does calling function return error?

First of all you are getting error here printerFunction(2) because printerFunction can not take any argument and If you want to give an argument then you can do it like:

func printerFunction(abc: Int) -> (Int) -> (){


}

And this will work fine:

printerFunction(2)

After that you are giving reference of that function to another variable like this:

let printAndReturnIntegerFunc = printerFunction() 

which means the type of printAndReturnIntegerFunc is like this:

Sample Image

that means It accept one Int and it will return void so this will work:

printAndReturnIntegerFunc(2)

How to collect the return value of a function (Swift 3)

You can return like below,

let userName = "Jake" //Global variable of the class
let userInfo = test() //Jake

func test() -> String { //single - element tuple will don't have label for return.

return self.userName
}

If you like to return with labels then you need tow or more return values like below,

   func test() -> (name:String,age:Int) {        
return (self.userName,125)
}

And access specific values by test().name

A func returning a func in Swift

The type signature of your first returnAFunc is () -> (), which means a function that takes no arguments and returns nothing. The type for your second function is () -> () -> (), which means a function that takes no arguments and returns a function with type () -> () (i.e. a function that takes no arguments and returns nothing).

I think your basic misunderstanding is that () represents a function type. Instead, it's the same thing as Void. Once you understand this, the only other potential "gotcha" is to remember that the arrow is right-associative.

EDIT: Since I got the checkmark, I think it's worth calling attention to IMSoP's answer, which does a great job of explaining how to read the type in more detail.

Xcode 8 :function types cannot have argument label breaking my build

The Swift designers decided to prohibit argument labels for function types.

The reasoning is explained here: https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md

This is a frustrating and questionable choice, as prohibiting argument labels makes it much easier to incorrectly invoke closures, which seems more important than simplifying the language's type system.

Usability > ideology.

Weird value of #function literal in Swift 3.1


Swift 5 update

In Swift 5 (not officially released yet, but you can pick up a master snapshot), this inconsistency is fixed thanks to #19062. Your code now outputs the following:

functionLiteralTest.weirdo()             // returns "weirdo()"
functionLiteralTest.weirdo(parameter: 1) // returns "weirdo(parameter:)"
functionLiteralTest.weirdo(1) // returns "weirdo(_:)"
functionLiteralTest.weirdo(1, 2) // returns "weirdo(_:_:)"

Pre Swift 5

I agree this is completely baffling behaviour, but it does appear to be intentional.

Function literals get "filled in" in the process of SILGen; and this is done through the SILGenFunction::emitLiteral function in SILGenApply.cpp.

This then calls onto getMagicFunctionString for a function literal:

static StringRef
getMagicFunctionString(SILGenFunction &SGF) {
assert(SGF.MagicFunctionName
&& "asking for #function but we don't have a function name?!");
if (SGF.MagicFunctionString.empty()) {
llvm::raw_string_ostream os(SGF.MagicFunctionString);
SGF.MagicFunctionName.printPretty(os);
}
return SGF.MagicFunctionString;
}

Which, if not already generated, creates a new stream to output to MagicFunctionString, and calls DeclName::printPretty on MagicFunctionName with this stream:

llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const {
return print(os, /*skipEmptyArgumentNames=*/true);
}

(MagicFunctionName is assigned when the function is emitted; and is given the value of getFullName(), which is just the Name of the declaration)

This then calls onto DeclName::print, which as its second parameter takes a boolean argument to determine whether to skip listing argument names if they're all empty:

llvm::raw_ostream &DeclName::print(llvm::raw_ostream &os,
bool skipEmptyArgumentNames) const {
// Print the base name.
os << getBaseName();

// If this is a simple name, we're done.
if (isSimpleName())
return os;

if (skipEmptyArgumentNames) {
// If there is more than one argument yet none of them have names,
// we're done.
if (getArgumentNames().size() > 0) {
bool anyNonEmptyNames = false;
for (auto c : getArgumentNames()) {
if (!c.empty()) {
anyNonEmptyNames = true;
break;
}
}

if (!anyNonEmptyNames)
return os;
}
}

// Print the argument names.
os << "(";
for (auto c : getArgumentNames()) {
os << c << ':';
}
os << ")";
return os;

}

And you can see that because of the if condition if (getArgumentNames().size() > 0), functions with no parameters will skip the check for all empty argument names, leading them to being emitted with parentheses, e.g weirdo(). But functions with one or more parameters, all with empty argument names, get emitted without parenthesis, e.g weirdo.

So, given DeclName::printPretty specifically passes true for the skipEmptyArgumentNames argument, it seems that the Swift team do specifically want this behaviour for #function.

Furthermore, if we look at the blame, we can see that DeclName::printPretty was added in this commit, with the commit message:

Pretty-print DeclNames with no keyword arguments by dropping the
parenthsized bit.

Instead of printing "f(_:_:)", just print "f".

That being said, I would still file a bug report over it, as it doesn't seem that intuitive for function literals.

Functions and returning values

So in Swift, a function that has no arrow has a return type of Void:

func funcWithNoReturnType() {
//I don't return anything, but I still can return to jump out of the function
}

This could be rewritten as:

func funcWithNoReturnType() -> Void {
//I don't return anything, but I still can return to jump out of the function
}

so in your case...

func deposit(amount : Double) {
balance += amount
}

your method deposit takes a single parameter of Type Double and this returns nothing, which is exactly why you do not see a return statement in your method declaration. This method is simply adding, or depositing more money into your account, where no return statement is needed.

However, onto your withdraw method:

func withdraw(amount : Double) -> Bool {
if balance > amount {
balance -= amount
return true
} else {
println("Insufficient funds")
return false
}
}

This method takes a single parameter of Type Double, and returns a Boolean. In regard to your withdraw method, if your balance is less than the amount you're trying to withdraw (amount), then that's not possible, which is why it returns false, but if you do have enough money in your account, it gracefully withdraws the money, and returns true, to act as if the operation was successful.

I hope this clears up a little bit of what you were confused on.

Function as return type Swift 4

You're right - when calling a function assigned to a variable (i.e. it's been returned from another function) you don't have parameter names. Though you can still hint to callers what the parameters are meant to be using an _ i.e. when returning a function directly

func userFactory(factoryName: String) -> (_ firstname: String, _ lastname: String) -> User {
return { firstname, lastname in
return User(factoryName, firstname, lastname)
}
}

Would be called like

let factory = userFactory(factoryName: "Factory")

let user1 = factory("John", "Doe")
let user2 = factory("Jane", "Doe")

The reason that you would use parameter names while inside your functionAsAReturnType method is because that's a function declared in scope, not assigned to a variable e.g.

func userFactory(factoryName: String) -> (_ firstname: String, _ lastname: String) -> User {
func inner(firstname: String, lastname: String) {
return User(factoryName, firstname, lastname)
}

// Look, parameter names :|
inner(firstname: "Bob", lastname: "Smith")

return inner
}

However, this rule doesn't apply if you declare your function like this:

func userFactory(factoryName: String) -> (_ firstname: String, _ lastname: String) -> User {
let inner = { (firstname: String, lastname: String) in
return User(factoryName, firstname, lastname)
}

// No parameters names here
inner("Bob", "Smith")

return inner
}

Here, you're not calling the declaration of the func inner (like the last example), you're calling the variable inner with some parameters.

You can see this with functions which already exist i.e.

// Calling a function defined on Int
let i = 1
i.distance(to: 100)

// But if you assign i.distance to a variable, you don't
// use the parameter names
let f = i.distance
f(100)

tl;dr - if you're calling a func, use parameter names. If you're using a variable which is a function, you don't.

Not sure if this helps, if not just let me know. Also let me know if I'm wrong about any of this :)

Do you always need to specify the type of the return value in a function?

Yes, you must always specify the return type unless the return type is Void.

It's necessary because Swift says it is required. It is a way to ensure the correct type is returned and the caller knows what type to expect. It's no different than declaring the type of any variable or function parameter.

It lets you catch many bugs at compile time and it avoids a lot of potential runtime issues.

Swift function with a function as parameter

First, your change doesn't do what the old code did. Your version returns the result of testing the first element in the list, not whether any of the elements pass the test.

The reason for the error is that your code isn't guaranteed to execute return at all. If the list is empty, then you'll drop to the end of the function without calling return. The compiler is telling you that.



Related Topics



Leave a reply



Submit