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:
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
Realitykit as a Framework to Build 3D Nonar Apps
Flip Arfaceanchor from Left-Handed to Right-Handed Coordinate System
Nsdata Contentsofurl Constructor Returns Nil
Collectionview Not Display Data After Parsing JSON
Save & Retrieve Tableviewcell Checkmark Using Nsuserdefaults in Swift
Executing Text-To-Speech in Order
Cannot Invoke 'Filter' with an Argument List of Type '((_) -> _)'
Swift Mutable Set: Duplicate Element Found
Swift- Variable Not Initialized Before Use (But It's Not Used)
Why Is It Legal to Mutate an Actor's Nonsendable Property
Turn for in Loops Local Variables into Mutable Variables
Swiftui Out of Index When Deleting an Array Element in Foreach
Swift Switch Statement Considered All Cases of Int, But Compiler Still Display Error
iOS 11 Large Title Navigation Bar Snaps Instead of Smooth Transition