Pardon me for jumping in without a whole load of quoting of previous messages 
but :

1. My mailbox is getting crammed with messages that are over 90% quote, 
sometimes running to hundreds of lines

2. I can't find a convenient message to attach this reply to


Matthew, please don't take any of the following as a personal attack of any 
kind but I am getting very concerned that this whole proposition is getting way 
too complicated for most programmers to cope. I can see a lot of them reverting 
to using whatever the default is for a given situation, only changing it if the 
compiler complains… and to hell with any thought of well written and protected 
code :-(

I hope I have got this right ; you are looking at separating scopes and 
capabilities? This is something I mentioned in my early attempts to communicate 
the problem of conflation of concerns over class visibility/ inheritability.

In the light of your proposal, may I contribute, what I hope is, a much simpler 
specification?

Starting with classes :

Since OO began, we have had the keywords: public, protected and private to 
control visibility; I am still not sure why we need to meddle with this well 
tried and tested model, apart from the consideration of extensions, but more on 
that later.

In C#, the only other visibility introduced was 'internal', to limit visibility 
to a given module, and a hybrid 'internal protected' which extended visibility 
of protected stuff to the module.

C# used 'sealed' to control inheritance, whereas Swift uses 'final'.

Still looking only at classes, I understand that Swift introduced 'open' and 
changed the meaning of 'public' to restrict the inheritability of a class to 
within its declaring module. This seemed odd as we already had 'final' for 
inheritance control, that could be used in conjunction with 'public' 
visibility, now to be confused with 'public' meaning 'public' inside a module 
but 'public final' from outside. Not forgetting 'open', which means public 
inside a module and public outside, but in its name, gives no indication 
whether it is a visibility specifier or an access control specifier.

If Swift really needs to control inheritability, then, as we seem agreed, this 
needs a separation of inheritability specifiers from visibility specifiers.

So, in considering the perceived need to be able to allow a class to be visible 
outside of a module whilst restricting its inheritability from code outside of 
the module, we now have an (extraneous) keyword that conflates visibility and 
inheritance control.

I would still argue strongly for the reinstatement of 'public final' to declare 
a class that is visible anywhere but that cannot be inherited, and 'public' to 
mean what it says on the tin (both in terms of visibility and inheritability).

Thus, using the "old" definition of 'public', we already had the following 
(module based) controls on classes :

internal class InternalClass // visibility - limited to the module : 
inheritable within the module
{
  internal func doIt() { } // visibility - limited to the module : overridable 
within the module
}

internal class InternalClass // visibility - limited to the module : 
inheritable within the module
{
  internal final func doIt() { } // visibility - limited to the module : not 
overridable
}

public class PublicClass // visibility - anywhere : inheritable anywhere
{
  internal func doIt() { } // visibility - limited to the module : overridable 
within the module
}

public class PublicClass // visibility - anywhere : inheritable anywhere
{
  internal final func doIt() { } // visibility - limited to the module : not 
overridable
}

public class PublicClass // visibility - anywhere : inheritable anywhere
{
  public func doIt() { } // visibility - anywhere : overridable anywhere
}

public class PublicClass // visibility - anywhere : inheritable anywhere
{
  public final func doIt() { } // visibility - anywhere : not overridable
}

The above declarations use clearly defined, separate, visibility and 
inheritability specifiers. Could you please say if I have missed any possible 
combinations?

So far, for classes, we have three visibility specifiers (private, public and 
internal) and one, separate, inheritance control specifier.


Extensions and Inheritance

Is it possible to state that inheriting from a class and creating an extension 
for a class are but two sides of the same coin? If so, can we treat such 
extension of any type commonly, so that we can use the same specifiers for 
protocols, classes, structs, enums, etc.

The one specifier that is missing from classes is commonly known as 'protected'

The one specifier that is missing from other types is one that limits 
visibility, to extensions to that type.

I suggested the 'extensible' specifier (or similar spelling), as a means of 
doing the same job that protected does for base classes, when extending any 
other type. Or could we reuse the 'final' keyword with any type, to mark either 
the type or any of its members, that we do not want to allow to be extendable?

This would mean that we can define non-class types, safe in the knowledge that 
another developer cannot add capabilities to that type that might affect any 
expected behaviour. At the moment, it is possible to do something like this :

// module 1
public struct Person
{
  public func doIt()
  {
    print("Person doIt")
  }
}

// module 2
protocol Imposter
{
  func doIt()
}

extension Person : Imposter
{
  func doIt()
  {
    print("Imposter doIt")
  }
}

No errors, no warnings, perfectly legitimate code that subverts the original 
intent of the type.

Swift doesn't normally allow you to "hide" or replace a base method as other 
languages do, unless you declare an extension that does the hiding for you.

However, if we could specify :

public struct Person
{
  public final func doIt()
  {
    print("Person doIt")
  }
}

Then the compiler could flag an error, should we try to write an extension with 
the intent of subverting the original method.

Likewise, as with a class, it could be possible to mark the whole struct as 
final, thus forbidding any extensions to it at all.


The remaining(?) part in the jigsaw is to:

1. limit access to members of types, other than classes, only to extensions

2. provide a common keyword to combine that principle with "protected" access, 
as found in classes


Example :

public struct Person
{
  extensible var name: String? // only visible in extensions
}

public class Person
{
  extensible var name: String? // replaces protected - only visible in 
subclasses or extensions
}

Summary

Visibility specifiers - public, internal, extensible, private

Inheritance control specifier - final


Question - do we really need much more than that? All this talk of submodules 
and file-based, directory-linked, etc, is starting to some more and more like 
the stringly-typed (identifying by strings) stuff that we have tried so hard to 
get rid of.

Please re-evaluate the myriad of options in the proposal, to see if they really 
need to be there, or whether they could be reduced to a much simpler solution 
:-)

--
Joanna Carter
Carter Consulting

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to