What Is the Usecase for Ignored Parameters in Swift

Swift default argument and ignore argument in protocol method/function

First of all, in the protocol, you are declaring "method", and the first parameter of "method" has no external name by default. So here is the very normal case code:

class SomeGame: Game {
func modeName(forRound: Int) -> ModeName {
// ...
}
}

let game: Game = SomeGame()
let modeName = game.modeName(1) // not `game.modeName(forRound: 1)`

In your OnlineGame case, if the parameter has default value, it has external name automatically even if it's the first parameter of the method. You can override that behavior with _ as explicit external name:

class OnlineGame : Game {
func modeName(_ forRound: Int = 0) -> ModeName {
//Some code
}
}

In your OfflineGame case, you can ignore the parameter with _ as internal name:

class OfflineGame : Game {
func modeName(_: Int) -> ModeName {
//Some code
}
}

How to compare enum with associated values by ignoring its associated value in Swift?

Edit: As Etan points out, you can omit the (_) wildcard match to use this more cleanly:

let number = CardRank.Number(5)
if case .Number = number {
// Is a number
} else {
// Something else
}

Unfortunately, I don't believe that there's an easier way than your switch approach in Swift 1.2.

In Swift 2, however, you can use the new if-case pattern match:

let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}

If you're looking to avoid verbosity, you might consider adding an isNumber computed property to your enum that implements your switch statement.

How to compare two strings ignoring case in Swift language?

Try this:

var a = "Cash"
var b = "cash"
let result: NSComparisonResult = a.compare(b, options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil, locale: nil)

// You can also ignore last two parameters(thanks 0x7fffffff)
//let result: NSComparisonResult = a.compare(b, options: NSStringCompareOptions.CaseInsensitiveSearch)

result is type of NSComparisonResult enum:

enum NSComparisonResult : Int {

case OrderedAscending
case OrderedSame
case OrderedDescending
}

So you can use if statement:

if result == .OrderedSame {
println("equal")
} else {
println("not equal")
}

How can I ignore a parameter in a URL?

If your revised question, you give us a URL of the following:

let string = "hxxps://ue.pt.com/v2/url?u=https-3A__oe.le.com_-3Fauthkey-3D-2521IB-2DCRV-2DqQ88-26cid-3DBACDF2ED353D-26id-3DBACDF2EFB61D353D-2521549-26parId-3Droot-26o-3DOneUp&d=DwMGaQ&c=WNpQK9bFmT89misLWAzsd66s44iGV-VujF_o4whjrfc&r=Ej_UhLznQMBqt3H3IYBQkjyx4xqdnS9mLiYA&m=HOBrLfxamFr4PYdACIR-A49th_oIe3MW69N7X-E&s=bXWSJ8gaSbKSlNuIf30S7Qsa6RcMKA-EOvP577XUyq0&e="

Clearly -3A__ is ://, _-3F is /?, -26 is &, -3D is =, etc. So if you do:

let replacements = [
"-3A__": "%3A//",
"_-3F": "/%3F",
"-26": "%26",
"-3D": "%3D",
"-2D": "%2D",
"-25": "%25"
]

let result = replacements.reduce(string) { (string, tuple) -> String in
return string.replacingOccurrences(of: tuple.key, with: tuple.value)
}

let components = URLComponents(string: result)!
for item in components.queryItems! {
print(item.name, item.value!)
}

You end up with call to hxxps://ue.pt.com/v2/url with the following parameters:

u https://oe.le.com/?authkey=%21IB-CRV-qQ88&cid=BACDF2ED353D&id=BACDF2EFB61D353D%21549&parId=root&o=OneUp
d DwMGaQ
c WNpQK9bFmT89misLWAzsd66s44iGV-VujF_o4whjrfc
r Ej_UhLznQMBqt3H3IYBQkjyx4xqdnS9mLiYA
m HOBrLfxamFr4PYdACIR-A49th_oIe3MW69N7X-E
s bXWSJ8gaSbKSlNuIf30S7Qsa6RcMKA-EOvP577XUyq0
e

The key here is that the parameters authkey, cid, id, parId, and o are for the oe.le.com URL, but all the other parameters, d, c, r, m, s, and e are not part of the URL encoded as part of u, but rather are separate parameters for the ue.pt.com URL. You do not want to include them as part of the URL for oe.le.com.

My original answer is below.


Let’s try approaching this problem from the other direction.

Consider these two scenarios where I’m building a URL. In the first, I have a single parameter to g.com which is u, which is a URL that has parameters:

var components = URLComponents(string: "http://g.com")!
components.queryItems = [
URLQueryItem(name: "u", value: "http://a.com/test?d=foo&e=bar")
]
let url = components.url

You’ll see that url is

http://g.com/?u=http://a.com/test?d%3Dfoo%26e%3Dbar

Note that the = and the & are percent escaped as %3D and %26, respectively because they are parameters to the URL buried inside the value associated with the u parameter, not actually parameters of the g.com URL itself.

The alternative scenario is that g.com’s URL has three parameters, u, d, and e:

var components2 = URLComponents(string: "http://g.com")!
components2.queryItems = [
URLQueryItem(name: "u", value: "http://a.com/test"),
URLQueryItem(name: "d", value: "foo"),
URLQueryItem(name: "e", value: "bar")
]
let url2 = components2.url

That yields:

http://g.com/?u=http://a.com/test&d=foo&e=bar

Note that the = and the & are not percent escaped because they are parameters of g.com URL, not parameters of the a.com URL contained with the u value.

You appear to be giving us a URL like generated by the second scenario, but insisting that it really is like the first scenario. If that’s true, the original URL has not been percent encoded correctly and is invalid. More likely, the second scenario applies and the parameters are of the g.com URL, not intended to be part of the u value.


For what it’s worth, note that you’ve given us a URL of:

hxxp://www.g.com/url?u=http://a.com/test&d=another

If d was really a parameter of the a.com URL, that URL would be http://a.com/test?d=another, not http://a.com/test&d=another (Note the ?, not &.)

So this is further evidence that the d parameter is really a parameter of the g.com url, and that the u parameter really is just http://a.com/test.

Why do I need underscores in swift?

There are a few nuances to different use cases, but generally an underscore means "ignore this".


When declaring a new function, an underscore tells Swift that the parameter should have no label when called — that's the case you're seeing. A fuller function declaration looks like this:

func myFunc(label name: Int) // call it like myFunc(label: 3)

"label" is an argument label, and must be present when you call the function. (And since Swift 3, labels are required for all arguments by default.) "name" is the variable name for that argument that you use inside the function. A shorter form looks like this:

func myFunc(name: Int) // call it like myFunc(name: 3)

This is a shortcut that lets you use the same word for both external argument label and internal parameter name. It's equivalent to func myFunc(name name: Int).

If you want your function to be callable without parameter labels, you use the underscore _ to make the label be nothing/ignored. (In that case you have to provide an internal name if you want to be able to use the parameter.)

func myFunc(_ name: Int) // call it like myFunc(3)

In an assignment statement, an underscore means "don't assign to anything". You can use this if you want to call a function that returns a result but don't care about the returned value.

_ = someFunction()

Or, like in the article you linked to, to ignore one element of a returned tuple:

let (x, _) = someFunctionThatReturnsXandY()

When you write a closure that implements some defined function type, you can use the underscore to ignore certain parameters.

PHPhotoLibrary.performChanges( { /* some changes */ },
completionHandler: { success, _ in // don't care about error
if success { print("yay") }
})

Similarly, when declaring a function that adopts a protocol or overrides a superclass method, you can use _ for parameter names to ignore parameters. Since the protocol/superclass might also define that the parameter has no label, you can even end up with two underscores in a row.

class MyView: NSView {
override func mouseDown(with _: NSEvent) {
// don't care about event, do same thing for every mouse down
}
override func draw(_ _: NSRect) {
// don't care about dirty rect, always redraw the whole view
}
}

Somewhat related to the last two styles: when using a flow control construct that binds a local variable/constant, you can use _ to ignore it. For example, if you want to iterate a sequence without needing access to its members:

for _ in 1...20 { // or 0..<20
// do something 20 times
}

If you're binding tuple cases in a switch statement, the underscore can work as a wildcard, as in this example (shortened from one in The Swift Programming Language):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
default:
print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}

One last thing that's not quite related, but which I'll include since (as noted by comments) it seems to lead people here: An underscore in an identifier — e.g. var _foo, func do_the_thing(), struct Stuff_ — means nothing in particular to Swift, but has a few uses among programmers.

Underscores within a name are a style choice, but not preferred in the Swift community, which has strong conventions about using UpperCamelCase for types and lowerCamelCase for all other symbols.

Prefixing or suffixing a symbol name with underscore is a style convention, historically used to distinguish private/internal-use-only symbols from exported API. However, Swift has access modifiers for that, so this convention generally is seen as non-idiomatic in Swift.

A few symbols with double-underscore prefixes (func __foo()) lurk in the depths of Apple's SDKs: These are (Obj)C symbols imported into Swift using the NS_REFINED_FOR_SWIFT attribute. Apple uses that when they want to make a "more Swifty" version of an (Obj)C API — for example, to make a type-agnostic method into a generic method. They need to use the imported API to make the refined Swift version work, so they use the __ to keep it available while hiding it from most tools and documentation.

Is there a performance improvement when using _ to ignore a parameter in Swift?

Generally, this falls under the category "micro optimization".
Even if there were a difference, it would probably be negligible
compared to the rest of your program. And chances are great that the
compiler notices the unused parameter and optimizes the code
accordingly. You should decide what parameter name makes the most
sense in your situation.

In this particular case, it does not make any difference at all.
How you name the (internal) method parameter affects only the compiling
phase, but does not change the generated code.

You can verify that easily
yourself. Create a source file "main.swift":

// main.swift
import Swift

func foo(str : String) -> Int {
return 100
}

func bar(_ : String) -> Int {
return 100
}

println(foo("a"))
println(bar("b"))

Now compile it and inspect the generated assembly code:


swiftc -O -emit-assembly main.swift

The assembly code for both methods is completely identical:


.private_extern __TF4main3fooFSSSi
.globl __TF4main3fooFSSSi
.align 4, 0x90
__TF4main3fooFSSSi:
pushq %rbp
movq %rsp, %rbp
movq %rdx, %rdi
callq _swift_unknownRelease
movl $100, %eax
popq %rbp
retq

.private_extern __TF4main3barFSSSi
.globl __TF4main3barFSSSi
.align 4, 0x90
__TF4main3barFSSSi:
pushq %rbp
movq %rsp, %rbp
movq %rdx, %rdi
callq _swift_unknownRelease
movl $100, %eax
popq %rbp
retq

How to reference multiple unnamed parameters inside a swift function

The parameters are called "ignored parameters", which are not meant to be referenced. See this answer for why ignored parameters are used.

From https://medium.com/swift-programming/facets-of-swift-part-4-functions-3cce9d9bba4, "An ignored parameter frees us of having to come up with a name for a parameter we don’t use, like when we override a method and don’t use a given parameter, or implement a closure and don’t use a given parameter. "

How to do an if-else comparison on enums with arguments

The trick is to not actually check with == but rather use the case keyword in conjunction with a single = in your if statement. This is a little counter intuitive in the beginning but just like if let, you get used to it pretty fast:

enum Normal {
case one
case two, three
}

enum NormalRaw: Int {
case one = 1
case two, three
}

enum NormalArg {
case one(Int)
case two, three
}


let normalOne = Normal.one
let normalRawOne = NormalRaw.one
let normalArgOne = NormalArg.one(1)

if case .one = normalOne {
print("A normal one") //prints "A normal one"
}

if case .one = normalRawOne {
print("A normal \(normalRawOne.rawValue)") //prints "A normal 1"
}

if case .one(let value) = normalArgOne {
print("A normal \(value)") //prints "A normal 1"
}

The point is that in Swift you only get equation of enums for free if your enum uses a raw type or if you have no associated values (try it out, you can't have both at the same time). Swift however does not know how to compare cases with associated values - I mean how could it? Let's look at this example:

Normal.one == .one //true
Normal.one == .two //false

NormalRaw.one == .one //true
NormalRaw.one == .two //false

NormalArg.one(1) == .one(1) //Well...?
NormalArg.one(2) == .one(1) //Well...?
NormalArg.one(1) == .two //Well...?

Maybe this makes it clearer why this cannot work out of the box:

class Special {
var name: String?
var special: Special?
}

enum SpecialEnum {
case one(Special)
case two
}

var special1 = Special()
special1.name = "Hello"

var special2 = Special()
special2.name = "World"
special2.special = special1

SpecialEnum.one(special1) == SpecialEnum.one(special2) //Well...?

So if you want enums with associated values, you'll have to implement Equatable protocol in your enum by yourself:

enum NormalArg: Equatable {
case one(Int)
case two

static func ==(lhs: NormalArg, rhs: NormalArg) -> Bool {
switch (lhs, rhs) {
case (let .one(a1), let .one(a2)):
return a1 == a2
case (.two,.two):
return true
default:
return false
}
}
}


Related Topics



Leave a reply



Submit