iosswifttuplesaccess-control

Property must be declared fileprivate because its type ... uses a private type


I just tried something to better understand access levels. In documentation for tuple's access level , there is a description from:

The access level for a tuple type is the most restrictive access level of all types used in that tuple.

Tuple types don’t have a standalone definition in the way that classes, structures, enumerations, and functions do. A tuple type’s access level is determined automatically from the types that make up the tuple type, and can’t be specified explicitly.

As I understand from this : A tuple type’s access level is determined automatically from the types that make up the tuple type, and can’t be specified explicitly.

So if i declare a tuples lik:

var tuples = (private access level , public access level)

Above tuples's access level must be private right?

When I try below code:

public class Main{
    var value1 : Int = 4
}

fileprivate class Main2{
    var value2: Int = 4 
}

private class Main3{
    var value3 : Int = 4
}

public class tupleExample {
    var tupleIs = (Main(),Main2(),Main3()) // this tupleIs's access level is internal here
}

Compiler gives me this error : Property must be declared fileprivate because its type '(Main, Main2, Main3)' uses a private type

I can fix this by adding access level to tupleIs property

 fileprivate var tupleIs = (Main(),Main2(),Main3())

But , as stated in the definition , A tuple type’s access level is determined automatically from the types that make up the tuple type, and can’t be specified explicitly. So compiler must be add private for tupleIs access level because most restrictive access level is private but it gives me an error.

My question is why I am getting a compiler error for this situation. Am i forgetting/missing somewhere?


Solution

  • You are mistaking the access level of a tuple property that you declare on a custom type with the access level of the individual elements of the tuple.

    The quote in your question refers to the access level of the individual elements of the tuple. Meaning that in your example, var tuple = (Main(),Main2(),Main3()), where Main is public, Main2 is fileprivate and Main3 is private, the access levels of the tuple elements will match that of their types:

    If you were to use a struct instead of the tuple with the following 3 properties, you'd also need to apply at least as restrictive access levels as the types of the properties:

    public struct Example {
      // This could be more restrictive than public (internal, file private, private)
      public let publicProperty: Main
      // This cannot be less restrictive than fileprivate, but can be more restrictive (private)
      fileprivate let fileprivateProperty: Main2
      // There is no more restrictive access control level than private, so this can only be private
      private let privateProperty: Main3
    }
    

    However, when declaring the tuple property on a custom type, you can control the access level of that property.

    public class tupleExample {
        public var tupleIs = (Main(),Main2(),Main3())
    }
    

    Same as if you were to declare the property with the struct type

    public class tupleExample {
      public let example: Example
    }
    

    But in either case, you will only be able to access the properties of the type (or the elements of the tuple) based on their own access level, not based on the access level of the enclosing type.

    So in case of the tuple example

    public class tupleExample {
        public var tupleIs = (Main(),Main2(),Main3())
    
        func accessProperties() {
          // Even though your `tupleIs` is accessible from outside the module, since it is public, not all of its properties are accessible outside the module
          print(tupleIs.0) // this is allowed from outside the module, since Main is public
          print(tupleIs.1) // this is only allowed inside the file, since Main2 is file private
          print(tupleIs.2) // this won't even compile, since you're trying to access a private property from outside its type
        }
    }
    

    And the same with the struct:

    public class tupleExample {
      public let example: Example
    
      func accessProperties() {
        // Even though `example` is accessible from outside the module, since it is public, not all of its properties are accessible outside the module
        print(example.publicProperty) // this is allowed from outside the module, since the property is public
        print(example.fileprivateProperty) // this is only allowed inside the file, since the property is fileprivate
        print(example.privateProperty) // this won't even compile, since you're trying to access a private property from outside its type
      }
    }
    
    

    TLDR: So the big difference between the access level of a tuple vs a custom type (class or struct) is that in a custom type, you can explicitly specify the access level of the property, but it has to be at least as restrictive as the type of the property. On the other hand, with a tuple, the access level of the elements of the tuple are all implicitly matching the access level of the element's type - you cannot make it more restrictive.