Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between @warn_unqualified_access and @warn_unused_result?

Tags:

swift

Can anyone explain with one example of warn_unqualified_access and warn_unused_result

like image 343
Padalingam Avatar asked Feb 18 '16 03:02

Padalingam


2 Answers

@warn_unused_result

Suppose you have an array representing a deck of cards:

var deck: [Card] = standardDeck.shuffled()

You want to write a function to deal a card to a player. You want to pull the “top” card from the deck, add it to the player's hand, and remove it from the deck:

func dealCard(to player: Player) {
    guard let card = deck.last else { fatalError("Ran out of cards") }
    player.hand.append(card)
    deck.dropLast()
}

When you test your app, you are puzzled. All your players' hands are filled with copies of the same card.

Being new to Swift, you think dropLast modifies deck by removing its last element. Sadly, you are mistaken. It returns a new array containing all but the last element of deck. (Technically it returns an ArraySlice.)

The compiler and the standard library have conspired to help you figure out the problem. The dropLast function is annotated with @warn_unused_result, so Xcode shows you a warning on the dropLast call:

.../Cards.swift:85:10: Result of call to 'dropLast()' is unused

Seeing the warning, you decide to option-click on dropLast and read the documentation, which tells you what dropLast does (returns a new array), and you realize you need to change the line to this:

    deck.removeLast()

Many, many functions, in the Swift standard library and in other libraries, are useful mainly for what they return. Ignoring the returned value of one of these functions is usually an error, so Swift makes it easy for the library author to warn the user about this behavior. In fact, Swift will probably soon be modified to apply @warn_unused_result by default, and to use a new @discardableResult attribute on the function to suppress the warning.

@warn_unqualified_access

You were so successful with your awesome card game on iOS that you've decided to port it to Mac OS X. On Mac OS X, you use NSView instead of UIView to show things on the screen. You're trying to figure out why your custom CardView is drawing itself incorrectly, so you want to call Swift's standard print function in drawRect:

class CardView: NSView {

    var card: Card

    override func drawRect(dirtyRect: NSRect) {
        print("Drawing \(card)")

        // drawing code here...
    }

    // rest of CardView here...
}

When you run your app, you're surprised to find that it pops up the print dialog! What's going on? The compiler and NSView have conspired to help you figure out the problem. The NSView.print function is annotated with @warn_unqualified_access, so Xcode shows you a warning on the print call:

.../CardView.swift:95:9: Use of 'print' treated as a reference to instance method in class 'NSView'

Seeing the warning, you option-click on print and read the documentation. You learn that NSView has its own print method, which lets the user print the contents of the view onto paper. How droll! Now you realize you need to change the call to explicitly use Swift's print function like this:

        Swift.print("Drawing \(card)")

(It is virtually impossible to develop for Mac OS X in Swift without running into this particular case. Repeatedly.)

This sort of problem is much less common than the other problem of ignoring a function's result. NSView.print is the only case that I can recall running into.

like image 195
rob mayoff Avatar answered Oct 31 '22 17:10

rob mayoff


Consider the following example:

class C { 
   @warn_unqualified_access func foo(x: Int) -> Int { return x } 
   @warn_unused_result func bar(x: Int) -> Int { return foo(x) } 
 } 

func main() {
  let c = C()
  c.foo(1)
  c.bar(1)
}

main()

This generates two warnings.

One in C.foo():

warning: use of 'foo' treated as a reference to instance method in class 'C' use 'self.' to silence this warning

This is because I declared foo as @warn_unqualified_access, so it means the compiler wants me to explicitly refer to the object when accessing said member. This is because - for example - calling print in a subclass of NSView conflicts between Swift.print and NSView.print

The second warning is generated in main(), when calling bar:

warning: result of call to 'bar' is unused c.bar(1)

This is because I am calling bar(), declared as @warn_unused_result, and then discarding its result. This is useful, for example, in methods which return you a new value but have no side effects. If you choose to ignore the new value, you essentially wasted work. The compiler can warn you to point that out.

like image 40
Enrico Granata Avatar answered Oct 31 '22 18:10

Enrico Granata