I just switch to Swift for couple days and I notice that the postfix and prefix ++ and -- will be removed in Swift 3. I have done some research and according to the announcement on the Swift website, the operator ++ and -- will be replaced by += 1 and -= 1. Link here New Features in Swift 2.2
I have a piece of code that work just fine with the old version of Swift. When I change from return counter1++ which is my original code to return counter1 += 1 and an error pops up saying
No '+=' candidates produce the expected contextual type 'Int'
Here is my example
func countingCounter() -> (() -> Int){
var counter1 = 0
let incrementCounter1: () -> Int = {
return counter1+=1 //original is counter1++
}
return incrementCounter1
}
I have tried to work this out but still stuck.
It clearly states in the Apple docs, copied here for your convenience:
NOTE
The compound assignment operators do not return a value. For example, you cannot write let b = a += 2.
No, the ++ operator is NOT the same as +=.
As said in my comment here is how you have to write it now to replace the postfix ++. ANother way would be to use an intermediary variable if you don't like the -1 thing.
let incrementCounter1: () -> Int = {
counter1+=1 //original is counter1++
return counter1-1;
}
No, they aren't identical, ++ and -- increment (or decrement) and return, += and -= add (or subtract) an amount in a simple to read short form, but they don't return anything.
So, you need to separate the value change from the value usage. Which is the whole point of the deprecation really - to make your code easier to read and maintain.
No they aren't identical, you have to increment first, then return the value.try this.
func countingCounter() -> (() -> Int){
var counter1 = 0
let incrementCounter1: () -> Int = {
counter1 += 1
return counter1
}
return incrementCounter1
}
Practicing necromancy here, but nobody mentioned defer yet - here's a slightly more elegant alternative to #Walfrat's method you may like the look of. Defer does the incrementing after returning the value.
let postIncrementCounter1: () -> Int = {
defer { counter1 += 1 } // original is counter1++
return counter1
}
Related
As of Swift 1.2, Apple introduces Set collection type.
Say, I have a set like:
var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5)
Now I want to get a random element out of it. Question is how? Set does not provide subscript(Int) like Array does. Instead it has subscript(SetIndex<T>). But firstly, SetIndex<T> does not have accessible initializers (hence, I can not just create an index with the offset I need), and secondly even if I can get the index for a first element in a set (var startIndex = set.startIndex) then the only way I can get to the N-th index is through consecutive calls to successor().
Therefore, I can see only 2 options at the moment, both ugly and expensive:
Convert the set into array (var array = [Int](set)) and use its subscript (which perfectly accepts Int); or
Get index of a first element in a set, traverse the chain of successor() methods to get to the N-th index, and then read corresponding element via set's subscript.
Do I miss some other way?
Starting with Swift 4.2, you can use randomElement:
let random = set.randomElement()
Probably the best approach is advance which walks successor for you:
func randomElementIndex<T>(s: Set<T>) -> T {
let n = Int(arc4random_uniform(UInt32(s.count)))
let i = advance(s.startIndex, n)
return s[i]
}
(EDIT: Heh; noticed you actually updated the question to include this answer before I added it to my answer... well, still a good idea and I learned something too. :D)
You can also walk the set rather than the indices (this was my first thought, but then I remembered advance).
func randomElement<T>(s: Set<T>) -> T {
let n = Int(arc4random_uniform(UInt32(s.count)))
for (i, e) in enumerate(s) {
if i == n { return e }
}
fatalError("The above loop must succeed")
}
In swift 3
extension Set {
public func randomObject() -> Element? {
let n = Int(arc4random_uniform(UInt32(self.count)))
let index = self.index(self.startIndex, offsetBy: n)
return self.count > 0 ? self[index] : nil
}
}
extension Set {
func randomElement() -> Element? {
return count == 0 ? nil : self[advance(self.startIndex, Int(arc4random()) % count)]
}
}
As per comments above re Swift updates, used a minor change for an extension to Set:
func randomElement() -> Element?
{
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
let index = startIndex.advancedBy(randomInt)
return count == 0 ? nil: self[index]
}
If you want a 'random' element from a Set then you use:
/// A member of the set, or `nil` if the set is empty.
var first: T? { get }
Get the 0th index or the 1,000,000th index makes no difference - they are all an arbitrary object.
But, if you want repeated calls to return a likely different element each time, then first might not fit the bill.
func mymethod(getno:Int)->(myval :Int,defaults :Int){
return (getno,8)
}
print(mymethod(getno: 2))
the output for the above program is
my val is 2 default is 8
ok, i can understand above program
but the below method is doubtful for me
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
i can't understand this line (var increment=makeIncrementer()) what's happening there ?
Is there somebody who can explain me this briefly?
makeIncrementer returns a function that accepts an Int and return an Int , so this
var increment = makeIncrementer()
makes increment variable to be equal to
func addOne(number: Int) -> Int {
return 1 + number
}
so increment(7) = addOne(7)
You may read Functions chapter in Swift book
You are not alone. I found it hard to wrap my head around this when I first started as well :)
What you are seeing is "a function returning another function". Think of functions as black boxes that take stuff in and spit stuff out. Now imagine passing these around as if they were values like 10 or "Hello".
makeIncrementer returns a function. Which function? This:
func addOne(number: Int) -> Int {
return 1 + number
}
See the line return addOne? That is not calling the function, but returning it!
So when you assign the return value of makeIncrementer to increment:
var increment = makeIncrementer()
increment now has the value of addOne. Calling increment would be the same as calling addOne. The above line is syntactically no different from:
var myString = getMyString()
The difference is that you are working with functions instead of strings.
Now you understand why increment(7) is 8.
If you want to burn your brain more, try looking up currying functions.
When I'm directly adding an integer value(i.e: 1,2,3,etc) with another integer variable
let arr:Array = ["One","Two"]
var valueT:Int64 = 0
value = arr.count + 1 //in this line
I get the following warning:
'+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
I fixed it the warning with this:
value = Int64(value + 1)
Though it is fixed but I wanna know why its called Mixed-type addition as I didn't use ++ . Also is there a better way to fix the warning in swift 3.1?
Update:
The following image is the proof of warning. I'm using Xcode Version 8.3 (8E162).
allROR is an array here.
Edit: To generate the error with your code it should be like
let value = 5
let result: Int64 = value + 1
Now you get the warning
'+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
But it is looks like warning is misleading, as of both value and 1 is of type Int so its summation also Int so you need to simply convert the result to Int64 and it is what you doing and that is perfectly ok.
let result: Int64 = Int64(value + 1)
Just to answer this part: why its called Mixed-type addition
With the simplified example by Nirav D:
let value = 5
let result: Int64 = value + 1
You can Command-click on + and see the generated interface of Collection:
(After Indexing has finished, of course.)
#available(swift, deprecated: 3.0, obsoleted: 4.0, message: "Mixed-type addition is deprecated. Please use explicit type conversion.")
public func +<T>(lhs: T.Stride, rhs: T) -> T where T : SignedInteger
So, in the code example above, the type of 1 is inferred as Int64, and as Int64.Stride == Int, the operation value + 1 matches the signature func +<T>(lhs: T.Stride, rhs: T) -> T where T : SignedInteger.
This deprecation is included in the revised version of SE-0104 Protocol-oriented integers, this part:
Standard Library no longer provides + and - operators for Strideable types.
They were problematic, as one could have written mixed-type code like
let x: Int64 = 42; x += (1 as Int), which would compile, but
shouldn't. Besides, since the Stride of an unsigned type is signed,
Standard Library had to implement a hack to make code like let x: UInt
= 42; x += (1 as Int) ambiguous. These operators were only necessary because they made advancing collection indices convenient, which is no
longer the case since the introduction of the new indexing model in
Swift 3.
As you already have seen, you can avoid this warning in many ways.
Data type is different that is why it is showing an error
you need to make both variable and constant of same data type
for e.g.
let result = value + Int64(1) //in this line
OK
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
i = arr.count + 1
}
gives as a warning '+' is deprecated: Mixed-type addition is deprecated. Please use explicit type conversion.
The reason is, that arr.count and i has different types. And this warning is right. It has nothing with the integer literal 1
this snippet gives you the warning too
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
i = 1
i += arr.count // here is the warning now
}
this will not compile, even though it looks very similar
var arr = [String]()
var i: Int64 = 0
if arr.count == 0 {
i = 1
} else {
let tmp = arr.count + 1
i = tmp
}
I hope we get an error message when we compose all of these snippets in the future release.
Let's say I do the following in C++:
int i = 1;
int* ptr = &i;
*ptr = 2;
cout << i << '\n';
And I want to do something similar in swift. Could I do the following?
var i : Int = 1
var iptr : UnsafeMutablePointer<Int> = &i
iptr.memory = 2
print(i)
And achieve the same result?
Yes-ish.
You can't do it exactly as you've attempted in the question. It won't compile. Swift won't let you directly access the address of a value like this. At the end of the day, the reason is mostly because there's simply no good reason to do so.
We do see the & operator in Swift however.
First of all, there is the inout keyword when declaring function parameters:
func doubleIfPositive(inout value: Float) -> Bool {
if value > 0 {
value *= 2
return true
}
return false
}
And to call this method, we'd need the & operator:
let weMadeARadian = doubleIfPositive(&pi)
We can see it similarly used when we have a function which takes an argument of type UnsafeMutablePointer (and other variants of these pointer structs). In this specific case, it's primarily for interoperability with C & Objective-C, where we could declare a method as such:
bool doubleIfPositive(float * value) -> bool {
if (value > 0) {
value *= 2;
return true;
}
return false;
}
The Swift interface for that method ends up looking somethin like this:
func doubleIfPositive(value: UnsafeMutablePointer<Float>) -> Bool
And calling this method from Swift actually looks just like it did before when using the inout approach:
let weMadeARadian = doubleIfPositive(&pi)
But these are the only two uses of this & operator I can find in Swift.
With that said, we can write a function that makes use of the second form of passing an argument into a method with the & operator and returns that variable wrapped in an unsafe mutable pointer. It looks like this:
func addressOf<T>(value: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return value
}
And it behaves about as you'd expect from your original code snippet:
var i: Int = 1
var iPtr = addressOf(&i)
iPtr.memory = 2
print(i) // prints 2
As noted by Kevin in the comments, we can also directly allocate memory if we want.
var iPtr = UnsafeMutablePointer<Int>.alloc(1)
The argument 1 here is effectively the mount of space to allocate. This says we want to allocate enough memory for a single Int.
This is roughly equivalent to the following C code:
int * iPtr = malloc(1 * sizeof(int));
BUT...
If you're doing any of this for anything other than interoperability with C or Objective-C, you're most likely not Swifting correctly. So before you start running around town with pointers to value types in Swift, please, make sure it's what you absolutely need to be doing. I've been writing Swift since release, and I've never found the need for any of these shenanigans.
Like this (not the only way, but it's clear):
var i : Int = 1
withUnsafeMutablePointer(&i) {
iptr -> () in
iptr.memory = 2
}
print(i)
Not a very interesting example, but it is completely parallel to your pseudo-code, and we really did reach right into the already allocated memory and alter it, which is what you wanted to do.
This sort of thing gets a lot more interesting when what you want to do is something like cycle thru memory just as fast as doing pointer arithmetic in C.
As of Swift 1.2, Apple introduces Set collection type.
Say, I have a set like:
var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5)
Now I want to get a random element out of it. Question is how? Set does not provide subscript(Int) like Array does. Instead it has subscript(SetIndex<T>). But firstly, SetIndex<T> does not have accessible initializers (hence, I can not just create an index with the offset I need), and secondly even if I can get the index for a first element in a set (var startIndex = set.startIndex) then the only way I can get to the N-th index is through consecutive calls to successor().
Therefore, I can see only 2 options at the moment, both ugly and expensive:
Convert the set into array (var array = [Int](set)) and use its subscript (which perfectly accepts Int); or
Get index of a first element in a set, traverse the chain of successor() methods to get to the N-th index, and then read corresponding element via set's subscript.
Do I miss some other way?
Starting with Swift 4.2, you can use randomElement:
let random = set.randomElement()
Probably the best approach is advance which walks successor for you:
func randomElementIndex<T>(s: Set<T>) -> T {
let n = Int(arc4random_uniform(UInt32(s.count)))
let i = advance(s.startIndex, n)
return s[i]
}
(EDIT: Heh; noticed you actually updated the question to include this answer before I added it to my answer... well, still a good idea and I learned something too. :D)
You can also walk the set rather than the indices (this was my first thought, but then I remembered advance).
func randomElement<T>(s: Set<T>) -> T {
let n = Int(arc4random_uniform(UInt32(s.count)))
for (i, e) in enumerate(s) {
if i == n { return e }
}
fatalError("The above loop must succeed")
}
In swift 3
extension Set {
public func randomObject() -> Element? {
let n = Int(arc4random_uniform(UInt32(self.count)))
let index = self.index(self.startIndex, offsetBy: n)
return self.count > 0 ? self[index] : nil
}
}
extension Set {
func randomElement() -> Element? {
return count == 0 ? nil : self[advance(self.startIndex, Int(arc4random()) % count)]
}
}
As per comments above re Swift updates, used a minor change for an extension to Set:
func randomElement() -> Element?
{
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
let index = startIndex.advancedBy(randomInt)
return count == 0 ? nil: self[index]
}
If you want a 'random' element from a Set then you use:
/// A member of the set, or `nil` if the set is empty.
var first: T? { get }
Get the 0th index or the 1,000,000th index makes no difference - they are all an arbitrary object.
But, if you want repeated calls to return a likely different element each time, then first might not fit the bill.