What is a good example to differentiate between fileprivate and private in Swift3

SwiftSwift3PrivateAccess ControlAccess Specifier

Swift Problem Overview


This article has been helpful in understanding the new access specifiers in Swift 3. It also gives some examples of different usages of fileprivate and private.

My question is - isn't using fileprivate on a function that is going to be used only in this file the same as using private?

Swift Solutions


Solution 1 - Swift

fileprivate is now what private used to be in earlier Swift releases: accessible from the same source file. A declaration marked as private can now only be accessed within the lexical scope it is declared in. So private is more restrictive than fileprivate.

As of Swift 4, private declarations inside a type are accessible to extensions of the same type if the extension is defined in the same source file.

Example (all in one source file):

class A {
    private func foo() {}
    fileprivate func bar() {}
    
    func baz() {
        foo()
        bar()
    }
}

extension A {
    func test() {
        foo() // Swift 3: error: use of unresolved identifier 'foo'
              // Swift 4: no error because extension is in same source file
        bar()
    }
}

let a = A()
a.foo() // error: 'foo' is inaccessible due to 'private' protection level
a.bar()
  • The private foo method is accessible only within the scope of the class A { ... } definition. It is not even accessible from an extension to the type (in Swift 3, see the second note below for changes in Swift 4).

  • The file-private bar method is accessible from the same source file.

Notes:

  1. The proposal SE-0159 – Fix Private Access Levels suggested to revert to the Swift 2 semantics in Swift 4. After a lengthy and controversial discussion on the swift-evolution mailing list, the proposal was rejected.

  2. The proposal SE-0169 – Improve Interaction Between private Declarations and Extensions suggests to make private declarations inside a type accessible to extensions of the same type if the extension is defined in the same source file. This proposal was accepted and implemented in Swift 4.

Solution 2 - Swift

I just draw a diagram about private, fileprivate, open and public

Hope it can quickly help you , for text description please refer to Martin R 's answer

[ Update Swift 4, 5 ]

enter image description here

Solution 3 - Swift

Updated for Swift 5

Private vs FilePrivate

For better clarity paste the code snippet in Playground

class Sum1 {
    let a: Int!
    let b: Int!
    private var result: Int?
    fileprivate var resultt: Int?
    
    init(a : Int, b: Int) {
        self.a = a
        self.b = b
    }
    
    func sum(){
        result = a + b
        print(result as! Int)
    }
}

let aObj = Sum1.init(a: 10, b: 20)
aObj.sum()
aObj.resultt //File Private Accessible as inside same swift file
aObj.result //Private varaible will not be accessible outside its definition except extensions

extension Sum1{
    
    func testing() {
        
        // Both private and fileprivate accessible in extensions
        print(result)
        print(resultt)
    }
}

//If SUM2 class is created in same file as Sum1 ---
class Sum2{

    func test(){
        
        let aSum1 = Sum1.init(a: 2, b: 2)
        // Only file private accessible
        aSum1.resultt
        
    }
}

Note: Outside of Swift file both private and fileprivate are not accessible.

Solution 4 - Swift

A practical rule of thumb is that you use private for variables, constants, inner structs and classes that are used only inside the declaration of your class / struct. You use fileprivate for things that are used inside of your extensions within the same file as your class/struct but outside of their defining curly braces (ie. their lexical scope).

    class ViewController: UIViewController {
        @IBOutlet var tableView: UITableView!
        //This is not used outside of class Viewcontroller
        private var titleText = "Demo"
        //This gets used in the extension
        fileprivate var list = [String]()
        override func viewDidLoad() {
            navigationItem.title = titleText
        }
    }

    extension ViewController: UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return list.count
        }
    }

Solution 5 - Swift

In Swift 4.0, Private is now accessible in extension but within same file. If you declare/define extension in other file, then your private variable will not be accessible to your extension**

File Private
File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.
Syntax: fileprivate <var type> <variable name>
Example: fileprivate class SomeFilePrivateClass {}


Private
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
Syntax: private <var type> <variable name>
Example: private class SomePrivateClass {}


Here is more detail about all access levels: Swift - Access Levels

Look at this images:
File: ViewController.swift
Here extension and view controller both are in same file, hence private variable testPrivateAccessLevel is accessible in extension

enter image description here


File: TestFile.swift
Here extension and view controller both are in different files, hence private variable testPrivateAccessLevel is not accessible in extension.

enter image description here

enter image description here


Here class ViewController2 is a subclass of ViewController and both are in same file. Here private variable testPrivateAccessLevel is not accessible in Subclass but fileprivate is accessible in subclass.

enter image description here

Solution 6 - Swift

Although @MartinR's and @StephenChen's answer are perfect, Swift 4 changes things a little bit.

Private is now considered as private to a class in which it is declared and also to its extensions.

FilePrivate is considered to be private in that file be it a class in which the variable is defined, it's extension, or any other classes defined in that same file.

Solution 7 - Swift

filePrivate - access controll level is within the file.

case 1: If we create extension with in same class file and try to access fileprivate function or fileprivate property in its extension - access allowed
case 2: If we create a extension of class in new file - And now try to access fileprivate function or fileprivate property - access not allowed

private - access control level is with in lexical scope

case 1: If property or function is declared as private in class - then scope is by default the class. case 2: if private instance is declared with in function body - then scope of instance is limited to function body.

Solution 8 - Swift

This is the explanation for swift 4. For swift 3, the difference is the private. swift 3 private cannot be accessed by its extension, only Class A itself can access.

enter image description here After swift 4, fileprivate becomes a bit redundant, because person normally will not define the subclass in the same file. Private should be enough for most cases.

Solution 9 - Swift

In the following example, language constructs modified by private and fileprivate seem to behave identically:

fileprivate func fact(_ n: Int) -> Int {
    if (n == 0) {
        return 1
    } else {
        return n * fact(n - 1)
    }
}

private func gauss(_ n: Int) -> Int {
    if (n == 0) {
        return 0
    } else {
        return n + gauss(n - 1)
    }
}

print(fact(0))
print(fact(5))
print(fact(3))

print(gauss(10))
print(gauss(9))

This is according to intuition, I guess. But, is there any exception?

Kindest regards.

Solution 10 - Swift

class Privacy {
    
    fileprivate(set) var pu:Int {
        get {
            return self.pr
        }
        set {
            self.pr = newValue
        }
    }
    private var pr:Int = 0
    fileprivate var fp:Int = 0
    
    
    func ex() {
        print("\(self.pu) == \(self.pr) and not \(self.fp)")
    }
}


extension Privacy {
    
    func ex2() {
        self.pu = 5
        self.ex()
    }
    
}

I like this because it is super simple for ivars.

Try changing fileprivate to private (and vice versa) and see what happens on compile...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNikita PView Question on Stackoverflow
Solution 1 - SwiftMartin RView Answer on Stackoverflow
Solution 2 - SwiftStephen ChenView Answer on Stackoverflow
Solution 3 - SwiftArpit JainView Answer on Stackoverflow
Solution 4 - SwiftJosh HomannView Answer on Stackoverflow
Solution 5 - SwiftKrunalView Answer on Stackoverflow
Solution 6 - SwiftNikita PView Answer on Stackoverflow
Solution 7 - SwiftAshish ChhabraView Answer on Stackoverflow
Solution 8 - SwiftWeidian HuangView Answer on Stackoverflow
Solution 9 - SwiftTomas BalderasView Answer on Stackoverflow
Solution 10 - SwiftCPDView Answer on Stackoverflow