I have a question about internal access control level
Internal is default access control level in Swift
so I think all of internal access control should be removed
Is there a specific case of using internal access control explicitly in Swift?
When or How I use internal access control in Swift?
I found a case internal needs to be added explicitly:
public internal(set) var myInt = 0
Omitting the internal keyword results in a compile error.
This is particular useful in a swift package/pod. The property is exposed publicly, but only inside the package/pod, the value can be changed.
As per documentation:
Default Access Levels
All entities in your code (with a few specific
exceptions, as described later in this chapter) have a default access
level of internal if you don’t specify an explicit access level
yourself. As a result, in many cases you don’t need to specify an
explicit access level in your code.
Source: https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html
As you mentioned, using the "internal" keyword has no effect other than making it clear that a function should never be made public in the future without careful consideration. At this point using the "internal" keyword is more about documenting and commenting your code.
When use default access level internal, no need to add internal explicitly.
This means that SomeInternalClass and someInternalConstant can be written without an explicit access-level modifier, and will still have an access level of internal. However the keyword "internal" is used just for developers understanding.
class SomeInternalClass {} // implicitly internal
let someInternalConstant = 0 // implicitly internal
Related
class ThermometerClass {
var temperature: Double = 0.0
func registerTemperature(_ temperature: Double) {
self.temperature = temperature
}
}
let thermometerClass = ThermometerClass()
thermometerClass.temperature = 56.0
thermometerClass.registerTemperature(56.0)
I can access temperature directly by using dot notation and also with the function what is the difference in this two.
The class member temperature is not well designed. It lacks encapsulation.
The direct access changes the variable with little control. You have to know the internals of the class to be sure that the change doesn't lead to an inconsistent state. You cannot totally prevent the attempt to set an illegal value very easily.
The access via the function is designed deliver some promises, regardless of the internal details. Access via a function is more controlled: if the change of the temperature would require additional information (e.g. hygrometry because you expect to correlate in time both measurements, or timestamp from an external atomic clock) the function could required it, whereas variables can always be changed individually.
Moreover, if the thermometer will one day get some special behavior (e.g. update the display in the user's preferred unit of measure, or raise an alarm under some conditions), the function could make sure it is done.
So the access via the function is the safer approach, since it will protect you against future evolution of that class.
This being said, the design of the class could be improved:
The encapsulation should be enforced, making the variable private. The class users would then be forced to the proper use of registerTemperature() .
For convenience, you could make a setter on a wrapper property: this seems to give direct public access to a variable but when its value is changed the setter is executed, to ensure the promises of such changes are held.
Edit to avoid ambiguous wording: property observers (willSet and didSet) allow to produce additional effects when a public variable is changed directly. So direct changes do not prevent additional effects. But this require the class designer to have such direct changes in mind. And the change is less controlled than in a function. For example, you cannot totally prevent the effects of an illegal change: you could reverse a wrong change in didSet, but willSet would then be called twice; once with the illegal value, one after the reversing.
What storage policy will variables declared in a local function inside a class have, static or automatic?
The "storage policy" is the lifetime. It will always be automatic. Section 8.6 of IEEE 1800-2012 states
The lifetime of methods declared as part of a class type shall be automatic. It shall be illegal to declare a
class method with a static lifetime.
You can declare a class method as being static, but in that context it means something entirely different. Section 8.10 states:
A static method is different from a task with static lifetime. The former refers to the lifetime of the method
within the class, while the latter refers to the lifetime of the arguments and variables within the task.
So, a static method can be called even if no objects of that class exist.
The local or protected attribute of a class member has no effect on the storage policy. It only affects the visibility of the identifier used to access the members.
That being said, the storage policy of a class member also affects the visibility of that identifier. So both features have the ability to restrict access, but for different reasons.
For example, you can never access an automatic variable from outside the scope of where it was declared. It does not matter if that scope is a class method, or a simple task. And it does not matter what the default lifetime of that scope was.
Conversely, if you declare a static variable in a scope, you might be able to access that variable from outside that scope, but you need to consider all the other visibility rules.
Specifically in regards to member variables, is there a difference between the following in Swift 3? In both cases, Foo is accessible by all code in that same file. Same thing with the implicitly-scoped 'laa' property, which seems to contradict the documentation.
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.
However, in both cases below, 'laa' is accessible from other classes in the same file implying that it is fileprivate, not private as the docs say the first one should be.
private class Foo
{
var laa:String
}
fileprivate class Foo
{
var laa:String
}
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.
Why does this compile?
internal class A {
public func f() {
}
}
I expected f's "public" modifier to be disallowed because its enclosing class is internal.
One motivation for allowing this is mentioned in SE-0025: Scoped Access Level (emphasis mine):
The compiler should not warn when a broader level of access control is used within a type with more restrictive access, such as internal within a private type. This allows the owner of the type to design the access they would use were they to make the type more widely accessible. (The members still cannot be accessed outside the enclosing lexical scope because the type itself is still restricted, i.e. outside code will never encounter a value of that type.)
So, although it doesn't change the accessibility of the members, it allows developers to communicate the access level they feel a given member should have if the enclosing type had a broader access level – which could for example be useful for APIs that currently have internal types which are planned to be made public in a future release.
The Swift reference says under the Guiding Principle of Access Levels,
No entity can be defined in terms of another entity that has a lower
(more restrictive) access level.
So, I suppose that doesn't mean that an entity can't be defined in terms of another entity that has a higher access level. In fact, that would surely be necessary.
In my Swift code, I often use the private modifier to limit the visibility of helper classes. For example, in one file, I'll have a GridController and a GridControllerModel.
The GridController (the UI) should be accessible to the rest of the application, but the model class is wholly internal and should never be accessed by the rest of the application.
I can address this in Swift by making both classes private and keeping them in the same file. But this gets unwieldy as classes get bigger. What I'd like to do is keep each class in a separate file (for programming convenience), but prevent access to the model class anything but GridController (for information hiding purposes).
Is there any way to do this in Swift?
As others have said, there is no way to do exactly what you want today in Swift.
One alternative is to use an extension in another file to add GridControllerModel as a nested subtype of GridController. e.g.
//GridControllerModel.swift
extension GridController {
struct GridControllerModel {
let propertyOne:String
let propertyTwo:String
}
}
This allows your GridController class in its own separate file to declare something like:
var model = GridControllerModel()
However, the rest of the application can still access the GridControllerModel type like this:
//SomeOtherClass.swift
var nested = GridController.GridControllerModel()
So, you do achieve some separation by making the model type a subtype of GridController, but it isn't true access control. On the plus side, it will not appear in code completion outside of the GridController class as "GridControllerModel", you would need to first type "GridController" and then "." to see the subtype "GridController.GridControllerModel"
It's also worth noting that an additional access control level is currently under review and likely to be in the next version of Swift (3.0) :
https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md
Assuming this proposal is accepted and implemented, you would be able to update your declared subtype like this:
//GridControllerModel.swift
local extension GridController {
struct GridControllerModel {
let propertyOne:String
let propertyTwo:String
}
}
(Note the "local" keyword above now). This would make the GridControllerModel type invisible and inaccessible to all classes except GridController and any extensions of GridController.
So, I would recommend that you consider this nested subtype approach today, because when Swift 3.0 arrives later this year, it's likely to support what you want by simply adding a keyword in front of your subtype declaration. And in the meantime, you get some of the separation you want as well.
No, there isn't an access modifier that restricts visibility to only a certain set of files. But you probably don't need that.
What does exist:
private: restricts visibility to within the same source file.
internal: restricts visibility to within the same module.
If you're building a piece of software that's too big for one source file, but both defines an outward-facing interface and internal details that should stay hidden from clients of that interface... then you're probably working at a level where it's appropriate to build a framework. Your framework can then define features that are internal for its use only and separate from the public interface it exposes to clients.