I'm writing a debugging function that will be called from other function in my project. This function is marked as #inline(__always), and does nothing if DEBUG is 0.
Does this function have any cost whatsoever at DEBUG == 0? I'm pretty sure that the answer is no, but I just want to confirm it.
tl;dr
Zero cost 🎉
Elaboration
I'm assuming your function looks something like this:
#inline(__always)
func myFunction() {
#if DEBUG
doStuff()
doStuff()
doStuff()
#endif
}
First, the preprocessor directives are followed. So if your DEBUG flag is 0, you can think of it as being preprocessed into this:
#inline(__always)
func myFunction() {
}
When you call myFunction anywhere, it's replaced with its contents at compile time. Assuming DEBUG is still 0, can think of it like this:
// What you wrote:
func myOtherFunction() {
print("Before")
myFunction()
print("After")
}
// Imagine it becoming this while compiling:
func myOtherFunction() {
print("Before")
print("After")
}
And, as you can see, the non-content of your inlined empty function are included, introducing zero cost to calling this function in this compilation environment.
Obviously, Swift code is not compiled into more Swift code. That's why I said you can imagine this; it's not truly what's happening. In actuality, it gets compiled into LLVM IR, but the end result is the same.
Related
I'm trying to execute both functions but when the first return true, the second function is not executed.
func run() {
if test1() || test2() {
doSomething()
}
}
func test1() -> Bool {
print("test1")
return true
}
func test2() -> Bool {
print("test2")
return false
}
func DoSomething() {
print("something")
}
Getting Result ::
test1
something
Wanted Result ::
test1
test2
something
In Android we can use one | do it. But not in swift, if someone knows how to do.
This is because the logical or stops its evaluation if the first operand is true. So, if test1 is true, test2 will not be evaluated at all. It's advisable to store the result of both functions into variables if you want to execute both and perform the or on those stored values.
In swift if functions are called in a lazy way. For your if it's enough of test1() to return true to know the result of the expression so there's no need to call test2(), that's why it's skipped
If you need both methods to be called for some reason, you can try this:
if [test1(), test2()].contains(true) {
doSomething()
}
This is called short-circuiting, and intentional. In principle it’s merely a performance optimization, but it has a semantic impact (which youre noticing here). In fact, it’s actually required by the specifications of many languages, including C, C++, Java, C++, etc.
The entire premise here is quite fishy. To have noticed that test2 doesn’t run, means that test2 has a side effect (in your example, printing a message). This is a violation of the principle of Command/Query separation. This is bad design, akin to having a ruler that drills the material it measures.
If you provide more detail as to what test1 and test2 actually do, we can probably suggest a better approach.
One of the most frustrating situations for me in Swift is when I have a class like this:
class A: NSObject {
var a: Int
override init() {
clear()
super.init()
}
func clear() {
a = 5
}
}
Of course, this causes multiple compiler errors ('self' used in method call 'clear' before 'super.init' call and Property 'self.a' not initialized at super.init call.
And changing the order of the constructor lines only fixes the first error:
override init() {
super.init()
clear()
}
Usually, I end up doing one of two things. The first option is to make a an implicitly unwrapped optional, but I feel that this is terrible style because a will never be nil after the constructor returns:
var a: Int! = nil
The second option is to copy the functionality of my clear() function in the constructor:
override init() {
a = 5
super.init()
}
This works fine for this simplified example, but it unnecessarily duplicates a lot of code in more complex code bases.
Is there a way to initialize a without duplicating my clear function or making a an optional? If not, why not?!
The "why not" in this specific case is very straightforward. What you've written would allow me to write this:
class B: A {
override func clear() {}
}
And then a would not be initialized. So what you've written can never be legal Swift.
That said, there's a deeper version that probably could be legal but isn't. If you marked the class final or if this were a struct, then the compiler might be able to prove that everything is correctly initialized along all code paths by inlining all the possible method calls, but the compiler doesn't do all that today; it's too complicated. The compiler just says "my proof engine isn't that strong so knock it off."
IMO, the correct solution here is a ! type, though I wouldn't add = nil. That's misleading. I would write it this way:
class A: NSObject {
var a: Int! // You don't have to assign `!` types; they're automatically nil
override init() {
super.init()
clear()
}
func clear() {
a = 5
}
}
This says "I am taking responsibility to make sure that a is going to be set before it is used." Which is exactly what you are doing. I do this all the time when I need to pass self as a delegate. I wish the compiler could explore every possible code path across every method call, but it doesn't today (and given what it might do to compile times, maybe I don't wish that).
but I feel that this is terrible style because a will never be nil after the constructor returns
That's exactly the point of ! types. They should never be nil by the time any other object can get their hands on it. If it could be nil, then you shouldn't be using !. I agree that ! is dangerous (since the compiler is no longer helping you), but it's not bad style.
The only other reasonable approach IMO is to assign default values. I wouldn't use the actual values of course; that would an invitation to subtle bugs. I would just use some default value to get things in place.
class A: NSObject {
var a = Int.min // -1 might be reasonable. I just like it to be clearly wrong
override init() {
super.init()
clear()
}
func clear() {
a = 5
}
}
I don't love this approach, though I've used it in a few places. I don't think it gives you any safety over the ! (it won't crash, but you'll almost certainly give you subtle behavioral bugs, and I'd rather the crash). This is a place where the programmer must pay attention because the compiler is powerful enough to prove everything's correct, and the point of ! is to mark those places.
What does a func with return type Never do?
For example:
func addNums() -> Never {
//my code
}
What will be the difference if I kept the return type as Void like this?
func addNums() -> Void {
//my code
}
Suppose I wish to handle a fatalError (as said by dpassage); the below code will be sufficient:
print("its an error")
return
Apple documentation says:
The return type of functions that do not return normally, that is, a type with no values.
Source: Developer
This was not a duplicate question of When and how to use #noreturn attribute in Swift?, as I wish for a more detailed answer which needs details like:
Practical examples on the difference between both Never and Void as return types
Condition by which we should adopt these return types.
Also there is a chance the return type can be nil; I need a comparison of that feature too
The answer should focus on the differences.
Never return type was introduced in Swift 3 to substitute #noreturn key.
See justification in this proposal:
SE-0102 Remove #noreturn attribute and introduce an empty Never type
As official documentation explains:
The return type of functions that do not return normally; a type with
no values.
Use Never as the return type when declaring a closure,
function, or method that unconditionally throws an error, traps, or
otherwise does not terminate.
Source: https://developer.apple.com/documentation/swift/never
Basic illustration:
// The following function is our custom function we would use
// to manually and purposefully trigger crash. In the logs,
// we can specify what exactly went wrong: e.g. couldn't cast something,
// couldn't call something or some value doesn't exist:
func crashApp() -> Never {
fatalError("Something very, very bad happened! Crash the app!")
}
Usage specifics and advantages over #noreturn, as referenced by Erica Sadun:
Never allows a function or method to throw: e.g. () throws -> Never. Throwing allows a secondary path for error remediation, even in functions that were not expected to return.
As a first class type, Never works with generics in a way that the #noreturn attribute could not.
Never proactively prevents a function from claiming both a return type and no-return at the same time. This was a potential issue under the old system.
First note (regarding secondary error remediation) is probably particularly important. Never function can have complex logic and throw – not necessarily crash.
Let's see some interesting use cases and comparison between Never and Void
Never
Example 1
func noReturn() -> Never {
fatalError() // fatalError also returns Never, so no need to `return`
}
func pickPositiveNumber(below limit: Int) -> Int {
guard limit >= 1 else {
noReturn()
// No need to exit guarded scope after noReturn
}
return rand(limit)
}
Example 2
func foo() {
abort()
print("Should not reach here") // Warning for this line
}
Example 3
func bar() -> Int {
if true {
abort() // No warning and no compiler error, because abort() terminates it.
} else {
return 1
}
}
abort() is defined as:
public func abort() -> Never
Void
These examples would not have been possible with it returning Void:
public func abortVoid() -> Void {
fatalError()
}
func bar() -> Int {
if true {
abortVoid() // ERROR: Missing return in a function expected to return 'Int'
} else {
return 1
}
}
And to pack it up with abort() returning Never:
func bar() -> Int {
if true {
abort() // No ERROR, but compiler sees it returns Never and warns:
return 2 // Will never be executed
} else {
return 1
}
}
We use Void to tell compiler there is no return value. Application keeps running.
We use Never to tell compiler there is no return to caller site. Application runloop is terminated.
Void
Void is itself a return type which is a tuple with zero elements. You can use Void and () interchangeably.
Look at these examples,
func yourFunc() {} This is a function without a return type, which basically returns a tuple with zero elements, that can be written as ()
func yourFunc() -> Void {} Function which is explicitly informing the compiler about return type of void
func yourFunc() -> () {} This return type of () displays the same as void type. () indicates a tuple with zero elements
Never
Never return-type informs the compiler that no need exists to return an empty tuple (). Also, function with the never return type is used for the exit point of the current execution like a crash, fatal error, abort or exit.
For a detailed understanding of never, let's have a look at an abort() example :
1.
func yourFunc() {
abort()
print("Will not reach at this point") //Warning for this line
}
2.
func yourFunc() -> Int {
if true {
abort()
} else {
return 1
}
}
From the above code snippets, we can see when we call abort() (which doesn't return a value) as the last statement in a function that expects a value to be returned (in our case Int). The compiler doesn't generate a warning.
abort()
public func abort() -> Never
Similarly for exit():
public func exit(_: Int32) -> Never
The apple documentation says: "Use Never as the return type when declaring a closure, function, or method that unconditionally throws an error, traps, or otherwise does not terminate."
So if you want to write a custom function that logs a catastrophic error, you should use the return type Never to signal to the compiler:
func catastrophicErrorDisplay(error: String) -> Never {
DisplaySomeCustomLogFacility(error)
}
In short "Never is used for sudden and total failure from which recovery is impossible."
To better understand Never and Void, and how Never is useful in more contexts than the old #noreturn was, let's first look at what the two types actually are defined as:
Never is defined here as:
public enum Never {}
Since there is no way to instantiate a value of an empty enum, the type system guarantees that no instance of Never can exist. This means functions that specify their return type as Never are prevented by the type system from actually returning under any circumstances.
The compiler takes this into account when doing control-flow analysis. For example, these two functions both compile without error, whereas they would fail if a function that returns Void was substituted for fatalError:
func foo(fail: Bool) -> String {
if fail {
fatalError()
} else {
return "foo"
}
// notice there is no return statement here
}
func bar(fail: Bool) -> Void {
let s: String
if fail {
fatalError()
// the compiler doesn't complain s is not initialized here
} else {
s = "bar"
}
print(s)
}
Void is defined here as:
public typealias Void = ()
There are no two different instances of an empty tuple. Thus, the return value of functions returning Void holds no information.
You can actually write return () or return Void(). You can also use the "value" returned, like this:
func empty() -> Void {}
let v = empty()
print(type(of: v)) // prints "()"
although the compiler will warn "Constant 'v' inferred to have type 'Void', which may be unexpected".
Defining both Never and Void in terms of the type system rather than as special language features enables us to do some pretty clever things with generics. Let's look at an example of a Result type, generic over both the success and failure type.
enum Result<R, E> {
case success(R)
case failure(E)
}
A possible specialization of this would be Result<Void, MyError>. This would mean you have a result that, on success, does not hold any information beyond the fact it succeeded.
Another possibility could be Result<String, Never>. This result is guaranteed by the compiler to never be the failure case.
Optionals interact with Never and Void in a similar way. Never? can only ever be nil, and Void? only holds the information wether it is nil or not, nothing more (it's basically a more complicated Bool). Both of these are not very useful on their own, but might appear when Never or Void are used as generic parameters somewhere.
In practice, you will rarely write functions returning Never. I have personally used it to wrap fatalError to create a function I use to mark functions that are not implemented yet:
func unimplemented(f: String = #function) -> Never {
fatalError("\(f) is not implemented yet")
}
Another example of a function returning Never is dispatchMain(), which can be used in command-line utilities to start the DispatchQueue.main. Since this queue then waits for new blocks, dispatchMain() never returns.
Never indicates that the function will never return. It's intended to be used for things like fatalError which cause your program to crash intentionally, often after logging an error. You probably shouldn't use it unless you're doing something like making a handler for catastrophic errors in your application.
This is different from a function which just doesn't return a value, as in your second snippet. You could also write that as func addNums() -> Void.
I am reading the Dancing in the Debugger — A Waltz with LLDB article. And I am trying the thread return command with Swift 2.2 as well as Swift 3.0.
My code is pretty simple:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let resust = test()
print(resust)
}
func test() -> Bool {
return true
}
}
and I added a breakpoint at the beginning of the test() function with a thread return false action. However, after command+R, my program stops at the breakpoint as expect, but with the following error:
"error: Error returning from frame 0 of thread 1: We only support setting simple integer and float return types at present.."
Here's a screen shot:
Then I tried the same in Objective-C code; everything goes well.
These are known bugs. The value types in Swift (Int, Bool, etc.) are all complex objects, and we haven't taught lldb how to overwrite the return values for them. Error handling will also make this tricky.
In general, forced returns are unsafe - more so with ARC and even more so with Swift, since you are likely to unbalance reference counts - not just on locals but potentially on objects passed in.
The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once is of no use if we I can change the value of token! And turning token into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>.
So should we give up on dispatch_once in Swift? Is there a safer way to execute code just once?
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
Static properties initialized by a closure are run lazily and at most once, so this prints only once, in spite of being called twice:
/*
run like:
swift once.swift
swift once.swift run
to see both cases
*/
class Once {
static let run: Void = {
print("Behold! \(__FUNCTION__) runs!")
return ()
}()
}
if Process.arguments.indexOf("run") != nil {
let _ = Once.run
let _ = Once.run
print("Called twice, but only printed \"Behold\" once, as desired.")
} else {
print("Note how it's run lazily, so you won't see the \"Behold\" text now.")
}
Example runs:
~/W/WhenDoesStaticDefaultRun> swift once.swift
Note how it's run lazily, so you won't see the "Behold" text now.
~/W/WhenDoesStaticDefaultRun> swift once.swift run
Behold! Once runs!
Called twice, but only printed "Behold" once, as desired.
I think the best approach is to just construct resources lazily as needed. Swift makes this easy.
There are several options. As already mentioned, you can initialize a static property within a type using a closure.
However, the simplest option is to define a global variable (or constant) and initialize it with a closure then reference that variable anywhere the initialization code is required to have happened once:
let resourceInit : Void = {
print("doing once...")
// do something once
}()
Another option is to wrap the type within a function so it reads better when calling. For example:
func doOnce() {
struct Resource {
static var resourceInit : Void = {
print("doing something once...")
}()
}
let _ = Resource.resourceInit
}
You can do variations on this as needed. For example, instead of using the type internal to the function, you can use a private global and internal or public function as needed.
However, I think the best approach is just to determine what resources you need to initialize and create them lazily as global or static properties.
For anyone who stumbles on this thread... We ran into a similar situation at Thumbtack and came up with this: https://www.github.com/thumbtack/Swift-RunOnce. Essentially, it lets you write the following
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
runOnce {
// One-time code
}
}
I also wrote a blog post explaining how the code works, and explaining why we felt it was worth adding to our codebase.
I found this while searching for something similar: Run code once per app install. The above solutions only work within each app run. If you want to run something once across app launches, do this:
func runOnce() {
if UserDefaults.standard.object(forKey: "run_once_key") == nil {
UserDefaults.standard.set(true, forKey: "run_once_key")
/* run once code */
} else {
/* already ran one time */
}
}
If the app is deleted and re-installed, this will reset.
Use NSUbiquitousKeyValueStore for tracking a value across installs and devices as long as user using same appleID.