Are Swift 4 custom argument labels ALWAYS required or just for disambiguation of functions? - swift

This question is similar to
Swift 4 custom argument labels - required?
but more specific. I came across that question when researching a problem caused by changing from a var (requiring no parameter) to a func (requiring a parameter) but missed changing all references. I have created a playground that contradicts the claim made in a subsequent edit to that question: "question is incorrect, as custom labels are mandatory"
My question is: how to correctly express what I observed, as demonstrated below:
class SomeTest {
static func someParam(p1: String?) -> String? {
return "hello \(p1 ?? "nothing")"
}
// Uncommenting the following causes error at let funny
// static func someParam(p2: String?) -> String? {
// return "hello \(p2 ?? "nothing")"
// }
static func doIt() {
let funny = someParam // ignoring the argument label is ok if there is no ambiguity
funny("thing") // and can be used without
someParam(p1: "thing2") // must have argument label
}
}
SomeTest.doIt()

If you have both someParam functions (each with a differently named parameter), then the line:
let funny = someParam
no longer works since it isn't known which of the two someParam functions you are referring to. This is solved by providing an unambiguous name:
let funny = someParam(p1:) // or someParam(p2:)
Note that funny has a type of (String?) -> String?. Both someParam functions have that same type. This is why you need to provide more detail to disambiguate the two. The parameter names don't change the function type.
When directly calling a function you must provide the full function name which includes any named parameter labels.
But when you create a closure variable and assign it the value of a function, you don't need to provide more than the base name of the function if that name is unambiguous in the given context.

Related

String property returning different values when used directly or in string interpolation

I've just finished debugging a situation where some of my labels were not displaying any text, despite the string in question definitely containing a value (it was printing the line before). I eventually pinned it down to returning different values depending on the way I accessed the string. Please note I'm not looking for ways to work around this, I am looking for a reason I am missing as to why this behaviour happens.
I had a protocol with the following optional String property, set to default to nil:
protocol SomeProtocol {
var titleString: String? { get }
}
extension SomeProtocol {
var titleString: String? {
return nil
}
}
Which was implemented in a class with a not optional String, with title set elsewhere:
class SomeClass: SomeProtocol {
var title: String
var titleString: String {
return title
}
}
When attempting to access the value of titleString from a SomeClass object, it always returned nil, regardless of the title property. This was seen through assigning to a label like:
label.text = someClassInstance.titleString
However, when I printed the value or set the label through
label.text = "\(someClassInstance.titleString)"
everything worked, and it displayed the text.
I've narrowed the source of this down to where I've overridden the optional property with one not optional. Clearly when I access the property directly it is returned by the protocol implementation, while using it by string interpolation returns the class one. What is actually behind this behaviour?
Edit: to demonstrate this behaviour run this gist in an Xcode playground:
https://gist.github.com/CaileanWilkinson/357c17f36d04b522b9bcf1241a825d9f
I feel like this is somewhat similar to the solution of this question of mine. In that question, there is also two almost identical properties - one optional, the other non-optional. And I experienced a similar situation where Swift can't figure out which property I want.
Your titleString in SomeClass is not overriding the titleString property in the protocol. This is reflected in Xcode's suggestions:
You can access both properties like this:
someObject.titleString as String // accesses the one in SomeClass
someObject.titleString as String? // accesses the one in the protocol
My point here is that the type of the expression matters. If the type of expression swift expects is String, then it resolves to the one in SomeClass. If the expected type of the expression is String?, then it evaluates to the one in the protocol.
This explains why setting the label's text without string interpolation will call the property in the protocol (label.text is String?, so it expects a String?) and why using string interpolation will call the property in SomeClass (String interpolation expects a non-optional).

Swift 3 first parameter names

In Swift 2, it appears that the first parameter name is not always required when calling a function. Now in Swift 3, the first parameter name is required when calling the function. For example:
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
Swift 2.2 allowed the function to be called by simply typing:
Frobnicate("Station")
Swift 3 seems to be requiring that we use the first parameter names of methods such as:
Frobnicate(runcible:"Station")
Is this the case with Swift 3 for all functions and methods or just certain situations?
Yes, this is right. Swift is fixing a language inconsistency this way (this was always required for initializers).
If you don't want to use the external parameter name, just remove it explicitly:
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
You can read the full rationale in Swift Evolution 0046
You can read The Swift Programming Language (Swift 3) in i-Book. Also you can check this out in WWDC 2016: What's New in Swift
In Swift 3, by default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.
fun greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
or
// This also works with Swift 2
fun addThreeNumber(_ first: Int, _ second: Int, _ third: Int) {
print(first+second+third)
}
addThreeNumber(1, 2, 3)
Exactly. In Swift 3.0, it's mandatory to write parameter names for all the parameters (including the first parameter). Parameter name is the one which is used inside the function implementation body.
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
By default, the external parameter label is same as the parameter name, if you don't specify any parameter label explicitly. Parameter label is the one which is used to pass the arguments while calling the function. If you need, for better clarity purpose, you can also specify external parameter labels explicitly. Example below-
func frobnicate(runcibleExternalLabel runcible: String) {
print("Frobnicate: \(runcible)")
}
If you want to skip the external parameter label while calling the function, just prepend a "_" before the parameter name.
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
Yes Swift 3 requires you to send First Parameter Label.
Please refer Swift 3 changes
The reason you want labels for parameters is so other code can supply parameters in any order.
Without labels, when you call the function the parameters are anonymous and you cannot be certain if you have supplied them in the wrong order.
Place labels in front of the parameters and code tools can do a much better job at catching errors us humans put in.
The underscore is just a way to cope with the transition from legacy code; method names including an Implicit first parameter. You should change any underscores that migration adds to your code to an explicit parameter label. You know it makes sense.

Swift: get the compile time name of variable (referencing to a class)

Is there a way to get the compile time name of a variable in Swift 2?
I mean the first variable name, which references to a new class instance, if any.
Here is a simple example:
public class Parameter : FloatLiteralConvertible {
var name:String?
var value:Double
// init from float literal
public required init (floatLiteral value: FloatLiteralType) {
self.value = Double(value)
self.name = getLiteralName()
}
func getLiteralName () -> String {
var literalName:String = ""
// do some magic to return the name
return literalName
}
}
let x:Parameter = 2.0
print(x.value) // this returns "2.0"
print(x.name!) // I want this to return "x"
I've already checked similar questions on that topic handling mirroring or objective-c reflections. But in all those cases, one can get only the property names in a class - in the example above name and value.
The same question has been asked in 2014 - Swift: Get Variable Actual Name as String
- and I hope, that since then there is a solution in swift 2.
No, there is no way to do that.
You have to understand that in the compiled state that variable usually does not exist. It can be optimized out or it is represented only as an item on the execution stack.
Even in languages with much better reflection that Swift has, usually you cannot inspect local variables.
To be honest, getting the name of a local variable dynamically has no practical use case.

Getting a function's return type in Swift

I realize that reflection isn't fully supported (yet) in Swift, but reflection run time methods are (apparently) supported. I'm trying to get the return type of a function at run time. Here's my example
let s:Selector = "willAnimateRotation"
var m:Method = class_getInstanceMethod(object_getClass(self), s)
let returnType = method_copyReturnType(m)
println("method: \(m); returnType: \(returnType)")
free(returnType)
Here's an example of my willAnimateRotation method, currently returning String:
private func willAnimateRotation() -> String {
return "abc"
}
The output of this does not seem to vary depending on the return type of the selector. E.g., with String or Void return type for the selector, I get the following output:
method: 0x0000000000000000; returnType: 0x0000000000000000
Thoughts?
ALSO: I'm actually not really trying to do this in Swift. I'm bridging an Objective-C class to Swift, and am getting the same results there, when the Objective-C code attempts to determine the return type of a Swift selector. That is, my end-goal in this case happens to be to use Objective-C to get the return type of a Swift selector.
OK. I've figured this out. The problem comes with my use of the "private" keyword. If you drop that and just use:
func willAnimateRotation() -> String {
return "abc"
}
The sample code above works fine.
In Swift you indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return.

What is the meaning of the '#' mark in swift language

I have seen code like this:
func hello(name: String, #helloMessage: String) -> String {
return "\(helloMessage), \(name)."
}
My question is what # mark means before parameter's name? Is that meaning that the parameter has to be specified when calling a function?
Moreover can anyone show me a difference with the function without this # mark? Code examples are more than welcome.
Update (Swift 3.*...)
the default behavior of the first parameter’s signature was changed drastically. To understand how argument labels (ex. “external parameters”) and parameter names (ex. “local parameters”) work, please read the chapter “Function Argument Labels and Parameter Names” from the Apple’s Swift-book.
Some examples:
func someFunction(parameterName: Int) { parameterName }
someFunction(parameterName: 5) // argument label not specified
func someFunction(argumentLabel parameterName: Int) { parameterName }
someFunction(argumentLabel: 5) // argument label specified
func someFunction(_ parameterName: Int) { parameterName }
someFunction(5) // argument label omitted
There is no difference in this behavior between methods and functions.
Update (Swift 2.*)
The feature described below was deprecated, one need to write the parameter name twice to get the same behavior as with hash symbol before.
Update (examples)
For functions: when the function is called and purpose of some parameters is unclear, you provide external names for those parameters.
func someFunction(parameterName: Int) { parameterName }
someFunction(5) // What is the meaning of "5"?
func someFunction(externalParameterName parameterName: Int) { parameterName }
someFunction(externalParameterName: 5) // Now it's clear.
But if external and local names are the same, you just write a hash symbol before the parameter name.
func someFunction(#parameterName: Int) { parameterName }
// It's actually like:
// func someFunction(parameterName parameterName: Int) { parameterName }
someFunction(parameterName: 5)
For methods: by default first parameter name is only local (like by functions), but second and subsequent parameter names are both local and external (like as you write a hash symbol before the parameter name, this # is implicitly there):
class SomeClass {
func someMethodWith(firstParameter: Int, andSecondParameter: Int) { ... }
}
SomeClass().someMethodWith(5, andSecondParameter: 10)
You can use # (or add an explicit external name) for the first parameter of the method too, but it'll not match Objective-C-style calling.
class SomeClass {
func someMethodWith(#firstParameter: Int, andSecondParameter: Int) { ... }
}
SomeClass().someMethodWith(firstParameter: 5, andSecondParameter: 10)
Original answer
If you want to provide an external parameter name for a function
parameter, and the local parameter name is already an appropriate name
to use, you do not need to write the same name twice for that
parameter. Instead, write the name once, and prefix the name with a
hash symbol (#). This tells Swift to use that name as both the local
parameter name and the external parameter name.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itunes.apple.com/ru/book/swift-programming-language/id881256329?l=en&mt=11
This has changed in Swift 2:
now you specify an external parameter name before the internal one, instead of using # to force the existing name.
According to the convention, the method name contains the action verb and the first parameter is not specified when calling the method:
func sayHiFrom(sender: String, to: String) {
print("Hi from \(sender) to \(to)!")
}
sayHiFrom("Jules", to: "Jim")
Specifying an internal parameter name
This time the second parameter has a different name for using inside the method, without changing the external name. When there is two names for a parameter, the first one is external and the second one is internal:
func sayHiFrom(sender: String, to receiver: String) {
print("Hi from \(sender) to \(receiver)!")
}
sayHiFrom("Jane", to: "John")
Forcing an external parameter name
You can force the first parameter to have an external name:
func sayHi(from sender: String, to receiver: String) {
print("Hi from \(sender) to \(receiver)!")
}
sayHi(from: "Joe", to: "Jack")
In this case, it's better that the method name does not contain the action term, because the forced parameter name already plays its role.
Forcing no external parameter names
You can also remove the parameter name for other parameters by preceding them with _ (underscore):
func sayHi(sender: String, _ receiver: String) {
print("Hi from \(sender) to \(receiver)!")
}
sayHi("Janice", "James")
**
Shorthand External Parameter Names
**
If you want to provide an external parameter name for a function parameter, and the local parameter name is already an appropriate name to use, you do not need to write the same name twice for that parameter. Instead, write the name once, and prefix the name with a hash symbol (#). This tells Swift to use that name as both the local parameter name and the external parameter name.
This example defines a function called containsCharacter, which defines external parameter names for both of its parameters by placing a hash symbol before their local parameter names:
func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
for character in string {
if character == characterToFind {
return true
}
}
return false
}
This function’s choice of parameter names makes for a clear, readable function body, while also enabling the function to be called without ambiguity:
let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
// containsAVee equals true, because "aardvark" contains a "v”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itun.es/in/jEUH0.l
With previous versions of Swift everything what #ovejka posted was true. In Swift 2.0 and above it looks like # is unused (in this or similar context, not counting #available)
I agree. It is confusing, but I hope this helps clear it up.
If you don't use #, you can enter parameters without using their names, as long as they are in order:
func x(a:Int, b:Int, c:Int) {some code}
x(10,20,30) or x(a:10, b:20, c:30) //Still have to be in order!
...but if you add #, the first variant is not allowed, i.e. x(10,20,30), as Swift now forces labels to be used. You can only use x(a:10, b:20, c:30).
Why would that be? Clarity. Makes code more readable.