Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
I like warnings. I really do. It reminds me that the compiler loves me and is looking out for me. (OK, the compiler at least tolerates me.)
What is a warning? It’s when the compiler notices that you’re doing something that might not be what you really intend. The compiler’s job, ultimately, is to do exactly what you tell it to do, but with being slabs of meat instead of computational machines we make mistakes. We make assumptions. Sometimes we’re careless. Sometimes we hold on to outdated ideas or techniques. If the compiler notices that might be sketchy, it lets you know.
Nothing makes me more depressed than joining a project where every build emits a stream of warnings. “Oh, you can ignore those” or “Yeah, we’re going to get around to fixing that.” And then I check the subversion log and see the warnings been in there for a year.
I think that’s a huge mistake. Warnings should either be fixed (they are showing a legitimate problem) or suppressed (we “know” this is OK, stop bugging me). Over my too-many years in this industry, I’ve had the opportunity to work on a lot of platforms. When I started my first job, our software ran on about 30 different Unix variants with at least a dozen different chip architectures. (Anyone remember Clipper?). A subsequent developer’s toolkit we sold supported about a dozen Unix variants, Mac, Windows, OS/2 (anyone remember that?), and VMS (anyone remember that?). I’ll let you ponder the testing matrix for that product.
Needless to say, I got to see a lot of cross-platform code. One interesting behavior we saw was that a warning on one platform’s compiler usually ended up as an error (or worse, a bug) on another platform, or sometimes even on a different rev of a vendor’s operating system. That’s what cemented my opinion of warnings: They’re there for a reason. Fix them.
The biggest problem I see with projects with large numbers of warnings, is that you might never notice new, legitimate warnings. Going from zero warnings to one warning is frightfully obvious. Going from one hundred warnings to one hundred and one warnings is much tougher to catch.
I’m not the only one who meditates on the warning. For example, Peter Hosey has a list of warnings he uses (and why).
For my own code, I tend to turn on -Wall
, with turns on a decent set of stable warnings. Weirdly, -Wall
does not actually mean all warnings. You can check out the docs at http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html for the complete list.
-Wall
, and friends like -Wextra
and -pedantic
, include a well-defined set of warnings, so you can assured that your code won’t generate new warnings with new versions of your compiler.
With Xcode 4.4, the Apple LLVM compiler introduced -Weverything
, which really means, “warn me about everything.” If the team adds new warnings and they get triggered by your code, you’ll see new warnings when you upgrade. I think this is wonderful. You should be careful anyway when upgrading compiler versions (software is software after all, and has bugs or new interpretations for corner-case behavior.) If I turn on -Weverything
I’m willing to take on that burden. I ported the Advanced Mac OS X Programming sample code to the latest Apple LLVM compiler and -Weverything
, and it was an eye-opening experience. It found all sorts of things.
In the real world, I probably won’t turn on -Weverything
for day-to-day work on a large project with lots of programmers. It’s very picky. But I’ve started going on occasional warning fix-its – turn it on, build, see what’s warned, and then fix it if appropriate. Then turn it off before committing the changes.
You can turn individual warnings on as well. Xcode provides checkboxes you can set, and you can supply them as command line parameters. Say you’re using -Wall
, but also wanted the warning that gives a little extra security on your printf
statements. You’d add -Wformat-security
to your build settings
Sometimes, though, you want to suppress some warnings. They might not make sense. For example, I consider -Wunused-parameter
to be worthless. It warns if you don’t consume all of the parameters passed to a function or method. More often than not, you’re passed more parameters than you need to do your work, especially in callback functions, or methods intending to be overridden.
There’s several ways to turn off warnings. You can uncheck the box in Xcode. Another is including the flag -Wno-unused-parameter
. The pattern is: for a warning called “badger
”, you turn it on with -Wbadger
, and suppress it with -Wno-badger
.
The Apple LLVM compiler is very helpful when it generates warnings – it tells you what warning triggered the message:
BNRExtremeGrooviness.m:181:69: warning: will never be executed [-Wunreachable-code]
awesome = [[BNRAwesome alloc] initWithName:@"Strongbad"];
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
That way, if you wanted to suppress this warning, you just need to stick a “no-
” in there, and supply the compiler the -Wno-unreachable-code
flag.
In fact, my usual compiler line for the updated Advanced book source code is something like
clang -g -Weverything -Wno-unused-parameter rest of the stuff
So why is this warning-flag-stuff useful information in the clicky-clicky world of Xcode project configuration? You might want to provide a company-wide set of warnings in .xcconfig
files. You can also suppress warnings on a case-by-case basis.
Consider this not untypical sockets code:
struct sockaddr_storage *serverAddress = ...;
struct hostent *host = ...;
serverAddress->ss_family = host->h_addrtype;
You get the struct hostent from a DNS lookup call like gethostbyname2
, and you create a server address, copying over the address family (such as AF_INET
for IPv4 or AF_INET6
for IPv6).
The problem is, h_addrtype
is an int, and ss_family
is a uint8_t
. So the top three (or more) bytes of the address type will be chopped off. As far as the networking API is concerned, that’s groovy. AF_INET
and friends are small values. But not as far as the compiler is concerned if you have -Weverything
turned on. It thinks that you might be making a mistake slicing off the top bytes (see the problems it can cause with BOOLS). So, with -Weverything
turned on, you’ll get this:
blorf.m:27:38: warning: implicit conversion loses integer precision: 'int' to 'sa_family_t'
(aka 'unsigned char') [-Wconversion]
serverAddress->ss_family = host->h_addrtype;
~ ~~~~~~^~~~~~~~~~
The compiler tells you the flag which would turn this warning on (so to turn it off just use -Wno-conversion
), but you might not want to turn it off project-wide (or even source-file wide), because there may be legitimate problems involving integer mutilation happening. You can turn warnings off on a case by case basis, by using compiler pragmas:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
serverAddress->ss_family = host->h_addrtype;
#pragma clang diagnostic pop
The syntax is pretty straightforward. #pragma clang diagnostic
says that you’re doing stuff with clang
, the name of the command-line Apple LLVM compiler tool.
The compiler keeps a stack of diagnostics, similar to Quartz graphic states. Push the current configuration, make some changes, enjoy the changes, then get rid of them, restoring the previous state. You can find full information at http://clang.llvm.org/docs/UsersManual.html
So here, I’m turning off the conversion warning just for this line of code. Of course, I could just cast it, but then I couldn’t use the cool #pragmas
.
Lastly, in my personal projects, I turn on the big warning hammer. -Werror
. Treat warnings as errors. This forces me to fix warnings as they happen. It forces strict warning hygiene.
(If you’re in Columbus, OH this weekend, come hear me speak at CocoaConf on the riveting topics of debugging and performance tuning!)
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...