In Swift 3, Is There a Difference Between 'Private Class Foo' and 'Fileprivate Class Foo' in Regards to Member Variables

In Swift 3, is there a difference between 'private class Foo' and 'fileprivate class Foo' in regards to member variables?

As said in this Q&A – there's no difference in the access levels between a top-level private and fileprivate declaration. private simply means that it's accessible only in the enclosing scope1, and at the top-level – the file is that scope.

Regarding the documentation comment:

If you define a type’s access level as private or file private, the default access level of its members will also be private or file private.

I would say this is incorrect, or at the very least misleading in the case of private. The scope in which a given type's members are visible is by default the scope that the type declaration itself is visible in (with the exception of access levels higher than internal).

Therefore the scope in which a private type's members are accessible is by default the enclosing scope that defines that type. At the top level, that's the file.

It's probably simpler just to say that type members default to being internal. Being declared in a type with a lower access level than this (such as private or fileprivate) just prevents the members from being visible outside of these access levels (as it makes no sense to refer to a given type's member without being able to see the type itself).


1. Note that in Swift 4, as per SE-0169, extensions of a given type that are declared in the same source file as the type have the same access control scope as the scope of the type declaration. Therefore they can access private members of the type.

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

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.

Distinction between private and fileprivate top-level classes

There is no difference in your case. The only time that fileprivate differs from private is inside a class, struct, or protocol.

What is the difference between private and fileprivate in Swift 4

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

Answer to your question:
(In Swift 3, private variables in a class are not visible in its extensions in the same file. For that, fileprivate had to be used.)

Yes, 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



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

Sample Image


File: TestFile.swift

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

Sample Image

Sample Image


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.

Sample Image

Swift: is there any functional difference between private static let (in a class definition) and fileprivate let (no owner)

The functional difference is minor: Your fileprivate (which could be private) global is accessible to all types defined within that file, whereas the former is limited to that one particular SomeClass.

The “private global” arguably requires non-local reasoning (i.e., you might have to scan through the whole file to see which types are there and might have access to it). On the other hand, the “private static property” makes the intent more clear at glance. As a result, many would favor this “private static property” approach.


For what it is worth, there is a hybrid approach:

class SomeClass {
var possibleValues: [String] {
return Self.someValues
}
}

private extension SomeClass {
private static let someValues: [String] = [
"mrah!",
"blah",
"shmah!"
]
}

It keeps the core type definition very clean, but keeps the namespace for the static constant. Sometimes it is nice to put various subtypes, methods, and statics in extensions within the same file. It can make it easy to grok the code, facilitates code folding, etc.

Difference between fileprivate and private extension?

The difference only crops up when we are talking about type members. private will restrict access to other methods within the same type definition, while fileprivate things are accessible by anything that lives in the same .swift file.

For things that live at the top level (outside of a type definition), private and fileprivate do exactly the same thing. So when you write

fileprivate extension Foo 
{
var aa: Int
{
return aaa + 10
}
}

private extension Foo
{
var aaa: Int
{
return 20
}
}

You really wrote

fileprivate extension Foo 
{
var aa: Int
{
return aaa + 10
}
}

fileprivate extension Foo
{
var aaa: Int
{
return 20
}
}

Ultimately, the two extensions on the same protocol get resolved by the compiler into a single extension.

fileprivate extension Foo 
{
var aa: Int
{
return aaa + 10
}
var aaa: Int
{
return 20
}
}

If you think think having two keywords like this is stupid, some Swift architects agree with you. I believe some style guides recommend you only bother using the public and private access modifiers (as well as the internal modifier, but that one is by default) because, in general, restricting things on a per-file basis, as opposed to a per-module or per-type basis is not particularly useful.

If you must use the fileprivate modifier, then never use the private modifier outside of a type scope. It’s confusing (since the private in that context “really” means fileprivate) and makes your code harder to read.

What's the access level of a case within a private enumeration

First of all, your code is completely artificial, as it would not even compile except in a playground — and in a playground the concepts of privacy are more or less meaningless. Test only within a real project.

When you do, you will have something like this:

private enum SomePrivateEnum {
case one
case two
case three
}
private class SomePrivateClass {
private var somePrivateProperty = 0
}
class ViewController : UIViewController {
func test() {
print(SomePrivateEnum.one)
print(SomePrivateClass().somePrivateProperty)
}
}

Now that we've established that, we can proceed to what's wrong with your test itself, namely that you are comparing apples with oranges. Here's the parallelism:

    print(SomePrivateEnum.one) // ok
print(SomePrivateClass()) // ok

So private for SomePrivateEnum and private for SomePrivateClass mean the same thing, namely: "private within this file". This code is in the same file so it can see both SomePrivateEnum and SomePrivateClass. (As the docs tell you, code that can see SomePrivateEnum can see SomePrivateEnum.one, and vice versa. So we are now comparing apples with apples.)

But private for somePrivateProperty means something else. It means "private within this type". So only code inside SomePrivateClass can see somePrivateProperty. This code is not inside SomePrivateClass, so it can't see that property.

Why does Swift allow access of private variables in the same file?

It isn't clear to me why private was originally implemented with regard to files, but rest assured that the Swift folks know this is not the only possible meaning of private and that it isn't ideal for some purposes, and are working to change it. There's already a proposal on the table, accepted for Swift 3, that will turn the current private into fileprivate and add a new level of private that will be scoped to the type rather than the file. You can expect to see this become part of Swift 3 in the very near future.



Related Topics



Leave a reply



Submit