Using Any instead of generics - swift

Generics
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.
Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout the Language Guide, even if you didn’t realize it. For example, Swift’s Array and Dictionary types are both generic collections. You can create an array that holds Int values, or an array that holds String values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be.
The Problem That Generics Solve
Here’s a standard, nongeneric function called swapTwoInts(::), which swaps two Int values:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
This function makes use of in-out parameters to swap the values of a
and b, as described in In-Out Parameters.
The swapTwoInts(::) function swaps the original value of b into a,
and the original value of a into b. You can call this function to swap
the values in two Int variables:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3" The
swapTwoInts(::) function is useful, but it can only be used with Int
values. If you want to swap two String values, or two Double values,
you have to write more functions, such as the swapTwoStrings(::) and
swapTwoDoubles(::) functions shown below:
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
My question:
Instead of using generics function we could have just used Any type as the argument type right, that will simple as this
func swapTwoInts(_a:inout Any,_b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
So how to plays important role in swift?
Can I write code without generics like this
var num = 3
var numtwo = 5
print(num)
print(numtwo)
func swap(_ a: inout Any, _ b: inout Any){
let tempA=a
a=b
b=tempA
}
swap(a: &num, b: &numtwo)

In swift, you can assign value to a variable ONLY if the type of the variable is same with the value. So imagine you have this:
var a = 1
var b = 2
func swapTwoValues(_ a: inout Any, _ b: inout Any) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&a, &b) // <- Cannot pass immutable value as inout argument: implicit conversion from 'Int' to 'Any' requires a temporary
So compiler forces you to implicitly assign Any for the type of the variables. This is not what you want I think. So you have to tell the compiler that it doesn't matter the type of the arguments. The only thing matters is they both have same type to fulfill compilers need. So to achieve this, you can use generic or some kind of protocol.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&a, &b) // Done
Tip: You can swap values with tuple in single line of code without using temporaryVar like this: (Even without function and generic and etc.)
(a, b) = (b, a)

Related

Currying func and keep param name/ label in Swift 4

In Swift 4, how can I curry func, and keep param label/ name:
func doSomething(a: A, b: B, c: C) {
}
let do_a = doSomething(a: value_a) // keep name a
let do_ab = do_a(b: value_b) // keep name b
let result = do_ab(c: value_c) // keep name c
With the answer from here Curry Function in Swift
And https://robots.thoughtbot.com/introduction-to-function-currying-in-swift
I can do, but the label is omitted
let curryDo = curry(doSomething)
let doA = curryDo(value_a) // but the a label is removed here.
How to keep param label/name in currying func?
Swift removed currying as a feature in version 3, and all current implementations use closures, which don't have labeled arguments.

Function external and internal parameter not mutable [duplicate]

I want make a function to swap 2 variables! but for new swift, I can't use 'var' ....
import UIKit
func swapF(inout a:Int, inout with b:Int ) {
print(" x = \(a) and y = \(b)")
(a, b) = (b, a)
print("New x = \(a) and new y = \(b)")
}
swapF(&5, with: &8)
Literals cannot be passed as inout parameters since they are intrinsically immutable.
Use two variables instead:
var i=5
var j=8
swapF(a:&i, with: &j)
Furthermore, with one of the last Swift 3 snapshots, inout should be placed near the type, the prototype of your function becomes:
func swapF(a:inout Int, with b:inout Int )

Is there any way to append an element/value to a tuple?

Is there anyway to add a new element to a tuple?
var tuple = (v1: 1,v2: 2)
tuple.v3 = 3 // Error
"error: value of tuple type '(v1: Int, v2: Int)' has no member 'v3'"
No. Each tuple with a different number of elements or a different type of elements represents a different type in the Swift type system. Hence, once you create a tuple, you cannot append elements to it, because that would change the type of the tuple.
Some really basic examples of tuples and their types:
let tupleWithTwoInts = (1,2) //has type (Int,Int)
let tupleWithThreeInts = (1,2,3) //has type (Int,Int,Int)
let tupleWithTwoStrings = ("a","b") //has type (String,String)
let tupleWithIntAndString = (1,"a") //has type (Int,String)
let tupleWithStringAndInt = ("a",1) //has type (String,Int)
Even the order of the elements make a difference in the type of a tuple.
type(of: tupleWithIntAndString) == type(of: tupleWithStringAndInt) //false
If you just need to support some small number of operations, then you can write a function for it.
For example, extending a 2D vector into 3D:
func expand(_ v: (x: Int, y: Int), z: Int) -> (x: Int, y: Int, z: Int) {
return (x: v.x, y: v.y, z: z)
}
While there is no extensible way to convert your array to a tuple as stated above, if you arrived at this question because you are making reusable components, and you like the convenience that variadic declarations can provide, you can move your method body into one that takes an array and let your variadic declaration be an alternate wrapper for the same method.
This
func buttonModels(_ buttonModels: ButtonModel...) {
self.buttonModels = buttonModels
}
Becomes:
func buttonModels(_ buttonModels: ButtonModel...) {
self.buttonModels(buttonModels)
}
func buttonModels(_ buttonModels: [ButtonModel]) {
self.buttonModels = buttonModels
}
It seems to me that you are looking to use a dictionary, not a tuple. See the docs: Tuple
EDIT: As pointed out, tuples can indeed be mutable if you declare them as a var and can be used to hold editable data. My bad!

Generic Where Clause Ambiguity with Associated Types in Swift

I was writing some example code in a playground and wanted a function that returns the distance between two values, both of which conform to the Strideable protocol in Swift so that I could use the distance(to other: Self) -> Self.Stride function. My implementation was as follows:
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U
{
return a.distance(to: b)
}
After observing this function for a while, I realized that I wasn't sure which Stride was being used in the where clause, the one from a or from b. From what I understand it would be possible for a and b to define different associated types for Stride. Also I haven't made any statements to ensure that a.Stride == b.Stride, although I understand that I could expand my where clause to do so.
So, which one would get used to check equivalence to U? To be clear, the question isn't about this particular code block, but rather any situation in which this ambiguity would exist.
a and b are the same type. If you wanted them to be different Strideable types you would add another generic parameter conforming to Strideable such that the function signature appears as follows:
func bar<T: Strideable, V: Strideable, U>(_ a: T, to b: V) -> U where T.Stride == U, V.Stride == U {
return a.distance(to: a) //Trivial return statement (see explanation below)
}
Although the aforementioned code would compile, return a.distance(to: b) would not compile because they (a and b) are different types and the definition of distance in Swift3 is public func distance(to other: Self) -> Self.Stride (note the use of Self which restricts other to the same type as the Strideable upon which this function is called). In conclusion, although you could make a and b different types, for your application it would not make sense to do so.
As further evidence for not being able to call your original posted code with different types please see the attached
Playground screenshot which shows an error when using different types.
However, this works fine in the playground.
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U {
return a.distance(to: b)
}
let doubleFoo: Double = 4.5
let intFoo: Double = 4
let g = distanceFrom(doubleFoo, to: intFoo) // gives me a double of -0.5
I hope this helps.

Swift functions accepting tuples

Is it possible to pass in a tuple into a function as long as their types match up?
When I try it, I get a missing argument in parameter error:
var myTuple = ("Text",10,"More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple)
It was possible, although was deprecated in Swift 2.2:
In Swift 2.1 and earlier it was possible to use a carefully crafted tuple to fill the parameters of a function. So, if you had a function that took two parameters, you could call it with a two-element tuple as long as the tuple had the correct types and element names.
...
This syntax — affectionately called “tuple splat syntax” — is the antithesis of idiomatic Swift’s self-documenting, readable style, and so it’s deprecated in Swift 2.2.
https://swift.org/blog/swift-2-2-new-features/
I came here wanting to know how to pass a tuple as a function parameter. The answers here focus on a different case. I'm not entirely clear what the OP was after.
In any case, here is how to pass a tuple as a parameter. And, for good measure, how to do it variadically.
func acceptTuple(tuple : (Int, String)) {
print("The Int is: \(tuple.0)")
print("The String is '\(tuple.1)'")
}
acceptTuple((45, "zebras"))
// Outputs:
// The Int is: 45
// The String is 'zebras'
func acceptTuples(tuples : (Int, String) ...) {
var index = 0
// note: you can't use the (index, tuple) pattern in the for loop,
// the compiler thinks you're trying to unpack the tuple, hence
/// use of a manual index
for tuple in tuples {
print("[\(index)] - Int is: \(tuple.0)")
print("[\(index)] - String is '\(tuple.1)'")
index++
}
}
acceptTuples((45, "zebras"), (17, "armadillos"), (12, "caterpillars"))
//Outputs
//[0] - Int is: 45
//[0] - String is 'zebras'
//[1] - Int is: 17
//[1] - String is 'armadillos'
//[2] - Int is: 12
//[2] - String is 'caterpillars'
Passing tuples in can be a quick and convenient approach, saving you from having to create wrappers etc. For example, I have a use case where I am passing a set of tokens and parameters to create a game level. Tuples makes this nice and compact:
// function signature
class func makeLevel(target: String, tokens: (TokenType, String)...) -> GameLevel
// The function is in the class Level. TokenType here is an Enum.
// example use:
let level = Level("Zoo Station", tokens:
(.Label, "Zebra"),
(.Bat, "LeftShape"),
(.RayTube, "HighPowered"),
(.Bat, "RightShape"),
(.GravityWell, "4"),
(.Accelerator, "Alpha"))
Yes, it's possible under these conditions:
the tuple must be immutable
the number of values in the tuple, their type, and their order must match the parameters expected by the function
named parameters must match external names in the function signature
non-named parameters must match parameters without external name in the function signature
So, your code is ok, the only thing you have to do is turning the tuple into an immutable one (i.e. using let and not var):
let myTuple = ("Text", 10, "More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple)
One more example with external names:
let myTuple = ("Text", paramB: 10, paramC: "More Text")
func myFunction(a:String, paramB b:Int, paramC c:String) {
// etc...
}
myFunction(myTuple)
In your tuple, it appears as though you must name them and then refer to them as such:
so your code should be
var myTuple = (val1: "Text", val2: 10, val3: "More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple.val1, myTuple.val2, myTuple.val3)
The tuple has named values (val1, val2, val3) which you set and then reference, when you pass in myTuple, to the function myFunction(), it appears as though you are just filling 1 of the 3 available arguements - and with the wrong type to boot! This is the equivalent of storing the types in a tuple, then taking them out for a function call. However, if you want a function to actually take a tuple as a parameter, see below:
var myTuple = (val1: "Text", val2: 10, val3: "More Text")
func tupleFunc(a:(String, Int, String)) {
}
tupleFunc(myTuple)
Yes, but that's the wrong structure: you're passing three variables called a, b, and c rather than a tuple with those components.
You need parentheses around the whole thing:
var myTuple = ("Text", 10, "More Text")
func myFunction(a:(x: String, y: Int, z: String)) {
println(a)
}
myFunction(myTuple)
You can use the following feature: Swift allows you to pass a function (f1) with any number of parameters (but without inout parameters) as a parameter of type (TIn) -> TOut to another function. In this case, TIn will represent a tuple from the parameters of the function f1:
precedencegroup ApplyArgumentPrecedence {
higherThan: BitwiseShiftPrecedence
}
infix operator <- :ApplyArgumentPrecedence
func <-<TIn, TOut>(f: ((TIn) -> TOut), arg: TIn) -> TOut {
return f(arg)
}
func sum(_ a: Int, _ b: Int) -> Int {
return a + b
}
print(sum <- (40, 2))
In swift 3.0, we should not able to pass the tuple directly to the function.If we did so, it shows the error message as "This type has been removed in swift 3.0"
func sum(x: Int, y: Int) -> Int
return x+y }
let params = (x: 1, y: 1)
let x = params.0
let y = params.1
sum(x: x, y: y)
Hope it helps you!!
The best option for now seems to be to just save it to a compound variable or use the build in dot syntax
let (val1, val2) = (1, 2)
func f(first: Int, second: Int) { }
f(first: val1, second: val2)
let vals = (1, 2)
f(first: vals.0, second: vals.1)
That feature called implicit tuple splat was removed in swift 3.
You can find more detailed explanation on the removal proposal here
Some suggestions to keep using tuple as an argument is by doing so:
func f1(_ a : (Int, Int)) { ... }
let x = (1, 2)
f1(x)
func f2<T>(_ a : T) -> T { ... }
let x = (1, 2)
f2(x)