Let's say I have the following function:
func update(a a: String? = nil, b: String? = nil) {
if a.notDefaultValue /* or something like that */ {
// ...
}
if b.notDefaultValue {
// ...
}
}
And I can call it in those ways (expecting to do as in the comments):
update() // Should do nothing
update(a: nil) // Should only go into first 'if' statement
update(b: nil) // Should only go into second 'if' statement
update(a: nil, b: nil) // Should go into both 'if' statements
update(a: "A") // Should only go into first 'if' statement
update(b: "B") // Should only go into second 'if' statement
update(a: "A", b: "B") // Should go into both 'if' statements
How can I achieve this?
EDIT:
The only way I could think of doing this is with method overload, but that is unfeasible when you have many parameters (don't even have to be that many, 4 will already need 17 methods).
I'm not sure why you would want to do this, but you can do it in this way:
let argumentPlaceholder = "__some_string_value__"
func update(a a: String? = argumentPlaceholder, b: String? = argumentPlaceholder) {
if a == argumentPlaceholder {
// Default argument was passed, treat it as nil.
}
if b == argumentPlaceholder {
// Default argument was passed, treat it as nil.
}
}
func update(a a: String?, b: String?) {
if let a = a, b = b {
print("a = \(a), b = \(b). a and b are not nil")
} else if let a = a {
print("a = \(a). b is nil")
} else if let b = b {
print("b = \(b). a is nil")
} else {
print("a and b are nil")
}
}
func update() {
print("no parameters")
}
update() // "no parameters\n"
update(a: nil, b: nil) // "a and b are nil\n"
update(a: nil, b: "Y") // "b = Y. a is nil\n"
update(a: "X", b: nil) // "a = X. b is nil\n"
update(a: "X", b: "Y") // "a = X, b = Y. a and b are not nil\n"
Also try to write something like this:
func hello() {
print("hello")
}
func hello(name: String) {
print("hello \(name)")
}
func hello(name: String, last: String) {
print("hello \(name) \(last)")
}
hello()
hello("arsen")
hello("arsen", last: "gasparyan")
It's more functional way
Related
I have an enum with associated value for some of the cases:
enum Foo {
case a
case b
case c(String?)
}
I also have a struct with this enum as a variable
struct Bar {
var foo: Foo
}
I then have an array of this objects
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
I want to create a function that operates on a subset of this array, based on the cases it receives something like
func printOnly(objectsWithCase: Foo)
So far its pretty simple, but now here's the catch: for this operation I WANT TO IGNORE the associated value.
I would like to make this function be able to take .c case without mentioning an associated value, as if to say "give me the ones with .c regardless of the associated values".
I other words - I'd like to pass in something like .c(_) (this doesn't work of course) and have it return (print in this case) both Bar(foo: .c(nil)) and Bar(foo: .c("someString"))
So far, I only came up with changing the functions declaration to take the filtering closure instead of the cases like this:
func printArray(array: [Bar], condition: (Bar) -> Bool) {
let tmp = array.filter(condition)
print(tmp)
}
I'm wondering if there's a way to do this in Swift, while passing the cases and not the condition block ?
You can use the underscore as a wild card in pattern matching operations:
array.filter {
switch $0.foo {
case .a: return true // keep a
case .b: return false // reject b
case .c(_): return true // keep c, regardless of assoc. value.
}
}
While this is not technically what you ask for (I don't think there's any way to achieve this with enums), you can write a "fake" enum that contains a wildcard c that will match anything you want. This will give you the exact same syntax.
1) Replace Foo with the following
struct Foo: Equatable {
let rawValue: String
let associatedObject: String?
let isWildcard: Bool
fileprivate init(rawValue: String, associatedObject: String?, isWildcard: Bool) {
self.rawValue = rawValue
self.associatedObject = associatedObject
self.isWildcard = isWildcard
}
static var a: Foo {
return Foo(rawValue: "a", associatedObject: nil, isWildcard: false)
}
static var b: Foo {
return Foo(rawValue: "b", associatedObject: nil, isWildcard: false)
}
static var c: Foo {
return Foo(rawValue: "c", associatedObject: nil, isWildcard: true)
}
static func c(_ value: String?) -> Foo {
return Foo(rawValue: "c", associatedObject: value, isWildcard: false)
}
}
func ==(left: Foo, right: Foo) -> Bool {
// Match rawValue + associatedObject unless we have a wildcard
return (left.rawValue == right.rawValue)
&& (left.associatedObject == right.associatedObject || left.isWilcard || right.isWildcard)
}
2) Implement your printOnly function with ==
func printOnly(objects: [Bar], with match: Foo) {
objects.filter { $0.foo == match }.forEach { print($0) }
}
3) Success
printOnly(objects: array, with: .c) // [.c(nil), .c("someString")]
Discussion
The main drawback of this method, besides the additional boilerplate code, is that you are forced to create an enum value that should not be allowed. This method puts the responsibility on you to use it only as a wildcard, and not as a real enum value. It will also not guarantee you that other enum cases cannot be created, although you should be able to mitigate that by making the only initializer fileprivate.
Otherwise, this gives you exactly the same interface and features an enum would give you, you can define your cases just as before
let array = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("Hello")]
Finally, you can still use it inside a switch, except you will always need to add a default statement.
switch Foo.c("Hello") {
case .a:
print("A")
case .b:
print("B")
case .c: // will match .c(nil) and .c("someString")
print("C")
default:
break
}
//: Playground - noun: a place where people can play
enum Foo {
case a
case b
case c(String?)
}
struct Bar {
var foo: Foo
}
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
func printArray(array: [Bar], condition: (Bar) -> Bool) {
let tmp = array.filter(condition)
print(tmp)
}
printArray(array: array) { bar in
switch bar.foo {
case .c:
return true
default:
return false
}
}
or
printArray(array: array) { bar in
if case let Foo.c = bar.foo {
return true
}
return false
}
EDIT
//: Playground - noun: a place where people can play
enum Foo: Equatable {
case a
case b
case c(String?)
}
func ==(lhs: Foo, rhs: Foo) -> Bool {
switch (lhs, rhs) {
case (.a, .a), (.b, .b), (.c, .c):
return true
default:
return false
}
}
struct Bar {
var foo: Foo
}
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
func printArray(array: [Bar], condition: (Bar) -> Bool) {
let tmp = array.filter(condition)
print(tmp)
}
func printOnly(objectsWithCase wantedCase: Foo) {
printArray(array: array) { bar in
if wantedCase == bar.foo {
return true
} else {
return false
}
}
}
printOnly(objectsWithCase:.c(nil))
I know what will happen with the cos and the {"cos(\($0))"} parts but I don't understand what will happen with the {_ in nil} part.
enum Operation {
case nullaryOperation(() -> Double, () -> String)
}
var operations: Dictionary<String,Operation> = [
"cos" : Operation.unaryOperation(cos, {"cos(\($0))"}, {_ in nil})
]
func performOperation(_ symbol: String) {
if let operation = operations[symbol] {
switch operation {
case .nullaryOperation(let function, let description):
accumulator = (function(), description(), nil)
}
}
}
As #CodeDifferent mentioned {_ in nil} syntax means: ignore whatever passed into this closure and always return nil.
Consider this simple functions that gives a closure as input.
func myFunc(inputClosure: (arg: Int?) -> Int?){
var num = inputClosure(arg: 2)
print(num)
}
The output is equal to the input:
myFunc { (arg) -> Int? in
return arg
}
No matter what the input is the output is 1000:
myFunc () { _ -> Int? in
return 1000
}
no matter what the input is the output is nil:
// These are the same:
myFunc { (arg) -> Int? in nil
}
myFunc { _ -> Int? in nil
}
I am serialising some json into objects with a failable json initialiser like this:
sections = {
let sectionJsons = json["sections"] as! [[String:AnyObject]]
return sectionJsons.map {
DynamicSection($0)
}
}()
DynamicSection's init:
init?(_ json:[String:AnyObject]) {
super.init()
//Boring stuff that can fail
I want to only append the DynamicSections that passed the init to sections. How can I accomplish this?
I can use filter+map like
return sectionJsons.filter { DynamicSection($0) != nil }.map { DynamicSection($0)! }
But that leads to initing the DynamicSection twice, which i'd like to avoid. Is there any better way to do this?
You can use flatMap:
return sectionJsons.flatMap { DynamicSection($0) }
Example:
struct Foo {
let num: Int
init?(_ num: Int) {
guard num % 2 == 0 else { return nil }
self.num = num
}
}
let arr = Array(1...5) // odd numbers will fail 'Foo' initialization
print(arr.flatMap { Foo($0) }) // [Foo(num: 2), Foo(num: 4)]
// or, point to 'Foo.init' instead of using an anonymous closure
print(arr.flatMap(Foo.init)) // [Foo(num: 2), Foo(num: 4)]
Whenever you see a chained filter and map, flatMap can generally be used as a good alternative approach (not just when using the filter to check nil entries).
E.g.
// non-init-failable Foo
struct Foo {
let num: Int
init(_ num: Int) {
self.num = num
}
}
let arr = Array(1...5) // we only want to use the even numbers to initialize Foo's
// chained filter and map
print(arr.filter { $0 % 2 == 0}.map { Foo($0) }) // [Foo(num: 2), Foo(num: 4)]
// or, with flatMap
print(arr.flatMap { $0 % 2 == 0 ? Foo($0) : nil }) // [Foo(num: 2), Foo(num: 4)]
For Swift 3.0 and above:
return sectionJsons.compactMap { DynamicSection($0) }
I'm new to Swift. Is it possible to have a function return by standard only 1 value and in some circumstances 2 or 3 values ?
You can return a tuple:
func functionThatReturnsTuple(numberOfElementsToReturn: Int) -> (String?, Int?) {
if numberOfElementsToReturn == 1 {
return ("One", nil)
}
if numberOfElementsToReturn == 2 {
return ("One", 2)
}
return (nil, nil)
}
You can return array:
func functionThatReturnsArray(numberOfElementsToReturn: Int) -> [String] {
if numberOfElementsToReturn == 3 {
return ["One", "Two", "Three"]
}
....
return []
}
Notice that both examples use optionals, make sure to handle them .
Alternatively you can use enum:
enum Value<A, B, C> {
case single(A)
case pair(A, B)
case triplet(A, B, C)
}
func yourFunc<A, B, C>(numberOfParameters: Int) -> Value<A, B, C> {
// determine how many params you need to return, and return them
}
And inn your outer code just check Value's case with switch of if case.
Is there a nicer way to do the assignment to DEF in the following example? I want to convert type A to Type B, but still preserve the nil possibility whenever I can.
Can't seem to stumble into a better way of doing this, however. Suggestions?
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue != nil ? Int(someValue) : nil
}
}
Swift 1:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map{Int($0)}
}
}
Swift 2:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map(Int.init)
}
}
map() takes an optional, unwraps it, and applies a function to it. If the optional resolves to nil, map() returns nil.
You are describing optional map:
var i: Int? = 2
let j = i.map { $0 * 2 } // j = .Some(4)
i = nil
let k = i.map { $0 * 2 } // k = nil
Think of this map like array or other collection map, where optionals are collections that have either zero (nil) or one (non-nil) element.
Note, if the operation you want to perform itself returns an optional, you need flatMap to avoid getting a double-optional:
let s: String? = "2"
let i = s.map { Int($0) } // i will be an Int??
let j = s.flatMap { Int($0) } // flattens to Int?