Swift errors using #if, #endif - swift

Using #if, #endif in Swift (using Xcode) produces errors if it cuts into the flow of an operation. This screenshot says it all:
Does anyone know a solution to make this example work, without repeating the entire code block twice? There can easily be situations where the entire block can be very large.
EDIT: My sample was a bit too simple. Here is a new sample where the "else if" depends on the same define (DEBUG). The "else if" must also be within the #if and #endif. And other samples can be much more complex than this.

Ideally, limit the usage of #if as much as possible. Using preprocessor directives is always a bit of a code smell. In this case, you can simply use a boolean variable:
#if DEBUG
let debug = true
#else
let debug = false
#endif
Then simply use the variable:
var a = 0
var b = 0
...
else if debug && a == b {
}
In release mode the code will become unreachable and the optimizer will remove it anyway.
With a bit of imagination, we can find other solutions, for example, we can move the check to a function:
func isDebugCheck(a: Int, b: Int) -> Bool {
#if DEBUG
return a == b
#else
return false
#endif
}
or we can move the whole code to a separate function and replace if-else by a return (or continue, depending on you needs), e.g.:
if a == 7 {
...
return
}
#if DEBUG
if a == b {
return
}
#endif
if ...

As #user28434 notes, there is no source-level pre-processor. This has gotten rid of a lot of very tricky pre-processor problems in C (such as bizarre needs for parentheses to make things work).
However, #if is integrated well into the language, and specifically supports switch for exactly these kinds of cases.
var a = 0
#if DEBUG
let b = 0
#endif
switch a {
case 7: a += 1
#if DEBUG
case b: a += 2
#endif
case 5: a += 3
default:
break
}

You can simply achieve this case with below code:
if a == b {
#if DEBUG
a += 2
#else
a += 1
#endif
} else if a == c {
a += 3
}

Related

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

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 +=

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.

How can I clear the swift warning "will never be excuted"?

Now I am learning the swift and when I use the if - else ,the Xcode shows me a warniing "will not be excuted".Though it isn't a big problem, I don't want to see this, how can I clear this warning in the project?
This is from a logic error that the compiler has picked up and is warning you about.
It gives the line number in your code that can never be reached.
a) Change the logic of your code
b) delete or comment out lines of code that can never be reached
The compiler will not give this message unnecessarily
example
if 1 == 2 {
a = 3
}
else {
a = 4
}
Obviously the condition is never met, the a=3 assignment can never happen.
let a = 3;
let b = 4;
if (a == 3) {
print("executed")
} else if (a == 5) {
print("never be executed")
} else {
print("not executed")
}
Apple's LLVM compiler is pretty verbose when it tells you about warnings - if you check the logs you would find something like:
warning: will never be executed [-Wunreachable-code]
So to suppres that warning, you need to set the flag -Wno-unreachable-code. This works for the ObjC compiler, but currently isn't supported by the Swift compiler

How to suppress a specific warning in Swift

I have a Swift function doing something like this:
func f() -> Int {
switch (__WORDSIZE) {
case 32: return 1
case 64: return 2
default: return 0
}
}
Because __WORDSIZE is a constant, the compiler always gives at least one warning in the switch body. Which lines are actually marked depends on the target I am building for (e.g. iPhone 5 vs. 6; interestingly iPhone 5 gives a warning for the 64-bit case whereas iPhone 6 gives two warnings for 32-bit and default).
I found out that the Swift equivalent for #pragma is // MARK:, so I tried
// MARK: clang diagnostic push
// MARK: clang diagnostic ignored "-Wall"
func f() -> Int {
switch (__WORDSIZE) {
case 32: return 1
case 64: return 2
default: return 0
}
}
// MARK: clang diagnostic pop
but the warnings remain, the MARKs seem to have no effect.
As a workaround, I now have something like this:
#if arch(arm) || arch(i386)
return 1
#else
#if arch(arm64) || arch(x86_64)
return 2
#else
return 0
#endif
#endif
– but of course this is not the same. Any hints…?
At present (Xcode 7.1), there seems to be no way of suppressing a specific warning in Swift (see e.g. How to silence a warning in swift).
In your special case, you can fool the compiler by
computing the number of bytes in a word:
func f() -> Int {
switch (__WORDSIZE / CHAR_BIT) { // Or: switch (sizeof(Int.self))
case 4: return 1
case 8: return 2
default: return 0
}
}
This compiles without warnings on both 32-bit and 64-bit architectures.

rust calling failure::fail_bounds_check with no-landing-pads flag enabled

I have been trying to write a basic kernel in rust and the link script fails with the following error:
roost.rs:(.text.kmain+0x12a): undefined reference to 'failure::fail_bounds_check::hee3207bbe41f708990v::v0.11.0'
I compile the rust source files with the following flags:
-O --target i686-unknown-linux-gnu -Z no-landing-pads --crate-type lib --emit=obj
If I understand the rust compiler correctly the -Z no-landing-pads option should stop the compiler from generating the failure functions. From testing I can tell that the failure function is only generated when the kmain function calls my function io::write_char(c: char)
This is the definition of io::write_char(c: char)
pub fn write_char(c: char) {
unsafe {
vga::place_char_at(c, vga::cursor_x, vga::cursor_y);
vga::cursor_y =
if vga::cursor_x >= vga::VGA_WIDTH {
vga::cursor_y + 1
} else {
vga::cursor_y
};
vga::cursor_x =
if vga::cursor_x >= vga::VGA_WIDTH {
0
} else {
vga::cursor_x + 1
};
vga::set_cursor_location(vga::cursor_x, vga::cursor_y);
}
}
How can I stop rust from trying to call the nonexistant function failure::fail_bounds_check?
Edit: further testing indicates that the vga::place_char_at function is the cause. Here is the code:
pub fn place_char_at(c: char, x: u8, y: u8) {
let tmpx =
if x >= VGA_WIDTH {
VGA_WIDTH - 1
} else {
x
};
let tmpy =
if y >= VGA_HEIGHT {
VGA_HEIGHT - 1
} else {
y
};
unsafe {
(*SCREEN)[(tmpy as uint) * 80 + (tmpx as uint)].char = c as u8;
}
}
From what I can tell the issue is that rust wants to bound check the array access I'm doing, is there a way to turn the assure the compiler that the checks have been done or turn off the feature for that function?
Edit2: So I solved it after some work. After digging around in the docs I found that rust has a function for vector access that bypasses bound checking. To use it I changed the place_char_at function to this:
pub fn place_char_at(c: char, x: u8, y: u8) {
let tmpx =
if x >= VGA_WIDTH {
VGA_WIDTH - 1
} else {
x
};
let tmpy =
if y >= VGA_HEIGHT {
VGA_HEIGHT - 1
} else {
y
};
unsafe {
(*SCREEN).unsafe_mut_ref((tmpy as uint) * 80 + (tmpx as uint)).char = c as u8;
}
}
Make sure you're linking to libcore. Also libcore has one dependency: a definition of failure. Make sure you mark a function #[lang="begin_unwind"] somewhere in your exception code. The requirement is that begin_unwind not return. See here for my example.
is there a way to ... turn off the feature for that function?
Nope. In the words of bstrie, if there were a compiler flag to eliminate array bounds checks, then bstrie would fork the language and make the flag delete your hard drive. In other words, safety is paramount.
You haven't described the type of SCREEN but if it implements MutableVector trait, what you probably want is to use an unsafe_set ( http://doc.rust-lang.org/core/slice/trait.MutableVector.html#tymethod.unsafe_set ):
unsafe fn unsafe_set(self, index: uint, val: T)
This performs no bounds checks, and it is undefined behaviour if index is larger than the length of self. However, it does run the destructor at index. It is equivalent to self[index] = val.