Why always prefix type property requirement with the static keyword in Swift protocol? - swift

On page 369 of the book The Swift Programming Language, it says “Always prefix type property requirements with the static keyword when you define them in a protocol.”
Example Code:
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
What is the reason or benefit of doing so?

Because without the static keyword you end up declaring an instance property rather than a type property. The example that immediately follows the paragraph you quote shows this:
Here’s an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}

Related

Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?

I'm following a tutorial on the protocol oriented programming paradigm in which I'm confused by something I thought was rather simple which is read only properties of protocols or getters and setters. My understanding is that a read only property is signified by using the keyword 'get' when declaring a variable within a protocol. I was excited so I quickly coded created a playground to see if my thinking was accurate however it appears that I can still change the property which I thought was read only. What am I doing wrong to make it a true read only property to where I can't set it?
protocol FullName {
var firstName: String {get set}
var lastName: String {get set}
var readOnlyProperty: String {get}
}
struct OuttaBeerOuttaHere: FullName {
var firstName: String
var lastName: String
var readOnlyProperty: String = "Jack! Jack!...Line from Titanic"
}
var leonardoDicaprio = OuttaBeerOuttaHere.init(firstName: "Leonardo", lastName: "Dicaprio", readOnlyProperty: "WTF")
print(leonardoDicaprio.readOnlyProperty) //prints "WTF"
leonardoDicaprio.readOnlyProperty = "what now"
print(leonardoDicaprio.readOnlyProperty) //prints "what now"
What am I doing wrong to make it a true read only property to where I can't set it?
There is a difference between a protocol (a set of rules) and the type (i.e. your struct) that adopts the protocol.
Your protocol rule says that readOnlyProperty should be readable.
Your struct obeys by making it readable, and also makes it writable. That is not illegal, so all is well — and readOnlyProperty in your struct is read-write.
What would have been illegal would be the inverse, i.e. for the protocol to declare a property read-write but the adopter to declare it read-only. That situation didn't arise in your example, but if it had, the compiler would have stopped you.
Your protocol doesn't declare readOnlyProperty as a read-only property. It only requires that implementations of that protocol have at least gettable readOnlyProperty property. To allow mutations of that property or not is up to implementation itself.
From Docs
Here’s an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}
The FullyNamed protocol requires a conforming type to provide a
fully-qualified name. The protocol doesn’t specify anything else about
the nature of the conforming type—it only specifies that the type must
be able to provide a full name for itself. The protocol states that
any FullyNamed type must have a gettable instance property called
fullName, which is of type String
it's a requirement from the protocol not a define

Declaration cannot be marked 'static', why

I have a School struct:
public struct School {
...
}
Then, I have an extension for it, in which I declare a static enum:
extension School {
// Compiler error: Declaration cannot be marked 'static'
static enum Level: String {
case Middle = "middle"
}
}
But I got compiler error as mentioned in comment above, how can I declare a static enum in extension then?
An enum is a type and hence it cannot be marked static. Even if you declare an enum inside a class, it will be accessible through the class type and not through an instance. In Swift, the static keyword can be used to mark type properties, but since enum is a type itself, it cannot be a property and hence cannot be marked static.
struct School {
}
extension School {
enum Level: String {
case Middle = "middle"
}
}
You can access the enum through the School type, you don't need to create an instance.
School.Level.Middle
Only properties and methods of a type can be marked static. (Enum is a value type like struct) In addition if you have a class that has a static method or property and require it to be subclassed it should be marked class and not static.
In Java, inner types have access to the members of the enclosing type. The static keyword is used to block such access and to indicate that the type is independent of the members of its enclosing type.
Swift doesn't do that from the start, so it doesn't have a use for static inner types.

Why is it recommended to prefix property requirements with static in Swift protocols?

In the Swift documentation section about Protocols, it is written that :
Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class
I don't understand if you should always do that or just in specific cases (because later in the docs, static isn't always there).
Why is it recommended to use static? What does it mean concretely?
Thank you.
EDIT : The same question applies to methods requirements.
later in the docs, static isn't always there
This section talks about type requirement, i.e. a requirement of the conforming type to have a static property of the specific name and type. In other words, when you write this
protocol MyProtocol {
static var myProperty: Int { get set }
}
the conforming class must do this
class MyClass : MyProtocol {
static var myProperty: Int
}// ^^^^^^
It also has an option to do this:
class MyClass : MyProtocol {
class var myProperty: Int
}// ^^^^^
but there is no such option when defining a protocol.
When static is not used, as happens later in the docs, the requirement becomes an instance requirement, not a type requirement:
protocol MyProtocol2 {
var myProperty2: Int { get set }
}
Now the class must provide an instance variable:
class MyClass2 : MyProtocol2 {
var myProperty2: Int
}
Note that there is a similar limitation on declaring instance requirements in protocols: you always use var, even though an implementation may use let to satisfy the requirement:
protocol MyProtocol3 {
var myProperty3: Int { get }
}// ^^^
class MyClass3 : MyProtocol3 {
let myProperty3 = 42
}// ^^^

Read-only properties of protocols in Swift

From the "Learn the Essentials of Swift" playground, there's an example protocol:
protocol ExampleProtocol {
var simpleDescription: String { get }
func adjust()
}
There's a short passage after this example that reads:
Note: The { get } following the simpleDescription property indicates that it is read-only, meaning that the value of the property can be viewed, but never changed.
Additionally an example is given of a class conforming to this protocol:
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
However how does this class conform to the protocol? What's stopping me from mutating simpleDescription? What don't I understand?
There's no way to specify in a protocol that you must have a read-only property. Your protocol asks for a simpleDescription property, and allows but does not require a setter.
Note also that the only reason you may mutate simpleDescription is because you know your a is of type SimpleClass. If we have a variable of type ExampleProtocol instead...
var a: ExampleProtocol = SimpleClass()
a.simpleDescription = "newValue" //Not allowed!
Protocols place requirements on object's interface, but do not restrict implementation from providing more operations than that.
In this example, the protocol requires a readable simpleDescription property and adjust() method. The class provides that, so it conforms to the protocol. In other words, this protocol says implementation must have get operation, but it does not prohibit them from also having set.
You will not be able to mutate simpleDescription via that protocol interface, because it does not provide such operation, but nothing prevents you from mutating it through different interface — in this example, the interface of the implementing class.
Found this and thought it may be of interest in addition to the excellent answer already provided:
If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 2.2).” iBooks. https://itun.es/us/jEUH0.l

How can I make the memberwise initialiser public, by default, for structs in Swift?

I have a Swift framework that defines a struct:
public struct CollectionTO {
var index: Order
var title: String
var description: String
}
However, I can't seem to use the implicit memberwise initialiser from another project that imports the library. The error is:
'CollectionTO' cannot be initialised because it has no accessible initialisers
i.e. the default synthesized memberwise initialiser is not public.
var collection1 = CollectionTO(index: 1, title: "New Releases", description: "All the new releases")
I'm having to add my own init method like so:
public struct CollectionTO {
var index: Order
var title: String
var description: String
public init(index: Order, title: String, description: String) {
self.index = index;
self.title = title;
self.description = description;
}
}
... but is there a way to do this without explicitly defining a public init?
Quoting the manual:
"Default Memberwise Initializers for Structure Types
The default memberwise initializer for a structure type is considered private if any of the structure’s stored properties are private. Otherwise, the initializer has an access level of internal.
As with the default initializer above, if you want a public structure type to be initializable with a memberwise initializer when used in another module, you must provide a public memberwise initializer yourself as part of the type’s definition."
Excerpt from "The Swift Programming Language", section "Access Control".
While it is not possible to have the default memberwise initializer at least you can make one quickly with the following steps:
UPDATE: Xcode 11 and later
As mentioned by Brock Batsell on the comments, for Xcode 11 and later all you need to is this:
Right click the class or struct name and choose refactor ->
Generate Memberwise Initializer
Xcode 10 and earlier answer
Make the object a class temporarily instead of a struct
Save
Right click the class name and choose refactor ->
Generate Memberwise Initializer
Change it back to a struct
We now have a ruby gem 💎 to parse a complete swift data model file, line-by-line, and add public access modifiers, public member-wise default initializers, and other things into a separate auto-generated output swift file.
This gem is called swift_republic
Please check out the following documentation for running this gem:
https://github.com/mehul90/swift_republic
Sometimes it's really annoying having an initializer when you don't need one. If you're constantly updating the variables to the object, it becomes bothersome very quickly to update the variables in 3 places (variable declaration, initializer parameter, and initializer implementation).
A workaround I've used for this issue is to have a static variable on the struct to act as (or essentially wrap) the "initializer". For instance:
struct MyStruct {
static var empty = Self()
static func empty(name: String) -> Self {
.init(privateName: name)
}
private var identifier: String = ""
}
Then you can call it similar to how you would an initializer (with autocomplete and everything!):
func someFunction(_ value: MyStruct) { ... }
//someFunction(.init()) -> ERROR, invalid due to `private` variable
someFunction(.empty)
someFunction(.empty(name: "Dan IRL"))
let myObject = MyStruct.empty
let myObject2 = MyStruct.empty(name: "Monty Python")
You have to define public init by yourself, luckily starting from Xcode 14 🥳 there is an automatic initializer completion (source - 60399329)