[swift-evolution] Simplifying Access Using 'Hidden'

Joanna Carter joanna at carterconsulting.org.uk
Mon Feb 13 17:04:33 CST 2017


What still strikes me as odd is that we now seem to have a plethora of visibilities, some of which do not provide for a given context, some of which seem to be looking for a context to justify their existence.

Whatever it is called, I find the idea of a file scope visibility somewhat bizarre and at odds with the principle of standard OO class encapsulation.

The two main reasons I can see for the perceived need for fileprivate are :

1. being able to separate out "sections" of a class into various extensions

2. giving global junkies the ability to write all their code in one unit

Surely, there are members of a type that the writer wants to remain private, even if an extension were declared in the same file. Fine, we have private for that and, even if the writer declares members to be fileprivate, there is no way that any extension declared outside of the file can see those members.

Now, I have a problem with that. If I want to access non-public members when I extend a type, either I declare those extensions in the same unit and declare those members as fileprivate, or if I want to declare those extensions in another file, I have to move up to the next suitable scope, which is internal.

But internal is too "open" because it allows, not only my chosen extensions to see those members but, also, any other code in the entire module.

Having made use of the "friend" concept in C++, this "all or next to nothing" approach to visibility seems to leave me in much the same place as Objective-C, where I could only have private or public, unless I did some tricky stuff with class extensions, something which really didn't look that pretty.

There are some parts of a type that I would want to remain really, really private to the type, not even visible to an extension.

There are other parts of a type that I would want to be private to that type but also visible in, but only in, extensions explicitly written against that type.

Which is why I am suggesting the "extensible" scope : private to the declaring type but also and only visible within any extension to that type.

Here follows a highly contrived example :

// Person.swift
public struct Person
{
  public var name: String
  
  public extensible(set) var dateOfBirth: Date
  
  public var age: Int
  {
    // return calculated age as of today
  }

  init(name: String, dateOfBirth: Date)
  {
    self.name = name
    
    self.dateOfBirth = dateOfBirth // accessible as if it were private
}

// Registrar.swift
extension Person
{
  func correct(dateOfBirth: Date)
  {
    self.dateOfBirth = …
  }
}

// Test.swift
{
  let person = Person()
  
  person.dateOfBirth = … // compilation error, not visible
}

IMHO, this then removes one use case for fileprivate in that it allows privileged visibility to private members of a type in extensions, both in the same file and in any other file. But, it also ensures that not other code is allowed access, whether that be in non-extension code in the same file or other non-extension code anywhere else.

As for case 2. for fileprivate, if a developer wants to put all sorts of globals and other code in one file, then I doubt if they are even going to bother to use fileprivate, especially when they get internal visibility with less typing ;)

Now, if someone could help me prepare this as a proposal…

--
Joanna Carter
Carter Consulting



More information about the swift-evolution mailing list