Type 'Int' does not conform to protocol 'BooleanType'? - swift

I know there is another thread with the same question, but it doesn't tell what is actually causing the problem
Im new to swift, so Im a bit confused on this.
I wrote a very simple program that is supposed to start with a default number of followers (0) and assign that to 'defaultfollowers' and once that becomes 1 its supposed become "followers", but I get the error "Type 'Int' does not conform to protocol 'BooleanType'". What is causing this and why
var followerdeafault = 0
var followers = 0
if (followerdeafault++){
var followers = followerdeafault
}

In Swift you can't implicitly substitute Int instead of Bool. This was done to prevent confusion and make code more readable.
So instead of this
let x = 10
if x { /* do something */ }
You have to write this:
let x = 10
if x != 0 { /* do something */ }
Also you can't pass an Optional instead of Bool to check if it's nil, as you would do in Objective-C. Use explicit comparison instead:
if myObject != nil { /* do something */ }

As the comments said, you're trying to use an Int in a Bool comparison statement. What you're looking for is probably something like this:
if followerdeafuaut++ == 1 { ... }
Also side note: the ++ operator is deprecated, moving towards using +=

Related

How do I define a constrained type in Swift?

I keep bumping onto this problem repeatedly. In real life I see sets of numbers that represent a particular quality but I have difficulties to express them as distinct type in Swift.
For example the percent type. Let says I would want to have a Percent type with only integers. Also this percent would never be able to go over 100 or below zero.
I could express that in pure C as a union, with members ranging from 0 to 100. However using the Swift enum for that with underlying value type doesn't seem to me like to correct approach. Or is it?
Let's pick another one. Bribor Interbank Interest rate. I know it will always be a range between 0 and 20 percent. But the number itself will be a decimal with two decimal places.
What's the correct way to deal with this problem in Swift? Generics perhaps?
As Michael says in the comment, probably something like this:
struct IntPercent {
let value : Int8
init?(_ v : Int) {
guard v >= 0 && v <= 100 else { return nil }
value = Int8(v)
}
}
(Note: use a struct, not a class for a base value like that)
If you do that a lot, you can improve that a little using protocols, like so:
protocol RestrictedValue {
associatedtype T : Comparable
static var range : ( T, T ) { get }
var value : T { set get }
init() // hack to make it work
}
extension RestrictedValue {
init?(v: T) {
self.init()
guard Self.range.0 <= v && Self.range.1 >= v else { return nil }
value = v
}
}
struct IntPercent : RestrictedValue {
static var range = ( 0, 100 )
var value : Int = 0
init() {}
}
I don't think you can use Generics to limit base type values.
But I bet there is an even better solution - this one is definitely not awezome :-)
Constraining the value of an object is not the same as a constrained type. Constraining values of numbers doesn't really make sense, as the things you are talking about are just numbers -- there is no such thing as a percent-number or a Bribor-Interbank-Interest-rate-number; they are just numbers. If you want to constrain their value, you do it wherever you get or use the numbers. It doesn't make sense to define a new type simply to constrain the values of an existing type.

Simple Pointer Operations in Swift?

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.

Conditional instructions in swift

I am trying to write in swift something that should be very basic, but I can't seem to get a handle on it :
First, I create a global variable. For example:
var xx:Int
Then, I want to create a conditional instruction. Something like :
if (xx == 1){
//do something
}
else if (xx == 2) {
//do something else
}
I can do this very easily in Objective-C, but I can't seem to be able to do it in Swift. I have looked everywhere, and don't seem to find the answer.
With the code you provided you're probably getting the error: "Variable xx used before initialized". This is happening because the declaration of the variable is incomplete, you neither gave a value to the variable nor told the compiler it is an optional. You have three options:
Give a initial value to it; var xx: Int = //value here
Declare it as an optional (doing this you say that it may not have a value, if it does the code will be executed, if it doesn't it won't); var xx: Int?
Force unwrap the variable (it still an optional, but if you force-unwrap it you're assuring the compiler that the variable will have a value when needed, otherwise it'll crash); var xx: Int!
Or you can say var xx = Int() that way it's initialized and the default initialization is equal to 0. This is different than the other answers and allows you to have a value from the get go if you're not sure what value might be assigned during runtime.
In addition to the other poster's point that you must assign an initial value before you can use xx, you also need to lose the parentheses around the condition in your if statement:
var xx:Int
xx = 2
if xx == 1
{
//do something
}
else if xx == 2
{
//do something else
}

Why doesn't this base type extension work?

Trying to play with extensions, but am having issues getting the following to work:
let value = -13
abs(value)
extension Int {
var abs:Int {
return abs(self) // -> Cannot invoke 'abs' with an argument list of type '(Int)'
}
}
value.abs
The compile error is weird, because it demonstrably runs the abs() function directly above with an Int as an argument. I've still got some light bulbs to trigger for generics I guess. Enlighten me.
The Swift compiler is confused that you use the abs variable as a function, which it cannot do. Now you could look at all the answers and rename your variable, but these do not give insight in how Swift functions work.
Swift automatically imports the Swift framework, where it defines its static functions. To use these functions, you usually do not need to specify that it's from the framework, but in cases like this, you should specify that you want to use the abs method from the Swift framework.
So after all the explanation, here's your code, which will work:
let value = -13
abs(value)
extension Int {
var abs: Int {
return Swift.abs(self)
}
}
value.abs
It appears just a call resolution problem. This will work:
let value = -13
abs(value)
extension Int {
var abs1:Int {
return abs(self)
}
}
value.abs1
And this will work too:
extension Int {
var abs:Int {
return self < 0 ? -self : self
}
}
value.abs
The problem here is that you are extending Int to add a variable named abs -- which is also the name of the function you are calling.
When you try to call the function abs() on the Int, it sees the variable abs that you created and it is confused because it thinks you are trying to return that variable and doesn't understand why you are sending it a parameter.
If you rename your variable to absoluteValue or anything else really, it should work.
let value = -13
abs(value)
extension Int {
var absoluteValue:Int {
return abs(self)
}
}
value.abs
Update: As others have stated, you can also solve the disambiguation of the use of abs by explicitly calling the function within the Swift framework. This should work just as well as the above solution.
let value = -13
abs(value)
extension Int {
var abs:Int {
return Swift.abs(self)
}
}
value.abs
Though, personally, I would still rename my new function to absoluteValue as in the first example so that its clear that you aren't calling the Swift.abs() when you use your abs variable.
Thanks to the direction of the original two answers (clash between global free function and the var I was defining), they have to be disambiguated. Rather than do my own inline implementation of abs or be forced to use a different name, I can properly scope the inside abs() using the Swift namespace.
extension Int {
var absoluteValue:Int {
return Swift.abs(self)
}
}
This gives me the best of both worlds (IMO).

Proper way to handle a fail to init

I am looking for a proper way to handle a invalid argument during a initialization.
I am unsure how to do it using Swift as the init has't a return type. How can I tell whoever is trying to initialize this class that you are doing something wrong?
init (timeInterval: Int) {
if timeInterval > 0
self.timeInterval = timeInterval
else
//???? (return false?)
}
Thank you!
Use a failable initializer. Such an initializer looks very similar to a regular designated initializer, but has a '?' character right after init and is allowed to return nil. A failable initializer creates an optional value.
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
See Apple's documentation on failable initializers for more detail.
In swift, you can't really abort a task half way through execution. There are no exceptions in swift and in general the philosophy is that aborting a task is dangerous and leads to bugs, so it just should't be done.
So, you verify a value like this:
assert(timeInterval > 0)
Which will terminate the program if an invalid value is provided.
You should also change timeInterval to be a UInt so that there will be a compiler error if anybody tries to give a < 0 value or an integer value that could be < 0.
It's probably not the answer you're looking for. But the goal is to check for bad parameters as early as possible, and that means doing it before you create any objects with those parameters. Ideally the check should be done at compile time but that doesn't always work.
I think this is the best solution, took it from:How should I handle parameter validation Swift
class NumberLessThanTen {
var mySmallNumber: Int?
class func instanceOrNil(number: Int) -> NumberLessThanTen? {
if number < 10 {
return NumberLessThanTen(number: number)
} else {
return nil
}
}
#required init() {
}
init(number: Int) {
self.mySmallNumber = number
}
}
let iv = NumberLessThanTen.instanceOrNil(17) // nil
let v = NumberLessThanTen.instanceOrNil(5) // valid instance
let n = v!.mySmallNumber // Some 5
In the Swift book by Apple, at the very bottom of this section:https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399
They say:
When to Use Assertions
Use an assertion whenever a condition has the potential to be false,
but must definitely be true in order for your code to continue
execution. Suitable scenarios for an assertion check include:
An integer subscript index is passed to a custom subscript
implementation, but the subscript index value could be too low or too
high. A value is passed to a function, but an invalid value means that
the function cannot fulfill its task. An optional value is currently
nil, but a non-nil value is essential for subsequent code to execute
successfully.
This sounds exactly like your situation!
Thus your code should look like:
init (timeInterval: Int) {
assert (timeInterval > 0, "Time Interval Must be a positive integer")
// Continue your execution normally
}