Declaration cannot be marked 'static', why - swift

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.

Related

Is there a CustomStringConvertible equivalent for type in Swift?

I want to implement a protocol similar to CustomStringConvertible for a given type but for instance.
My need is to display type properties values without creating an instance valuer for this purpose. Of course I can add CustomStringConvertible protocol to this type then create an instance value only to invoke description. But I wonder if there is such feature in Swift?
Overview:
type(of:) is a function that returns the type of an instance in a String
self can be used on the Type
Code:
struct Something {
}
print(type(of: Something.self))
Create your own protocol that will include a static var.
static var desc: String { get set }
on classes that conform to your protocol use it like this:
MyClass.desc

Swift 3: private required initializer possible?

Consider following code:
private class MyClass {
private required init(_ i: Int) {
}
}
Now, I'm getting compiler error:
'required' initializer must be as accessible as its enclosing type. But the type is declared as private.
I thought the issue might be that the class is declared on a file level, so it's
private type
restricts the use of an entity to the enclosing declaration.
as documentation says. So it effectively makes it fileprivate, since the enclosing declaration is a file. But I'm getting the same error even for nested private classes.
When I declare initializer as fileprivate it works:
private class MyClass {
private class MyNested {
fileprivate required init(_ i: Int) {
}
}
}
Question: why private is not correct here? Is it possible to declare private required initializer?
I ask because I want to understand the error in the first place.
Why I need it is rather different question, but initially I wrote such code:
private class MyClass {
private class MyNested {
private init(_ i: Int) {
}
func foo() {
var f = type(of: self).init(1)
}
}
}
and then had to add required declaration specifier as I was getting the error: constructing an object of class type 'MyClass.MyNested' with a metatype value must use a 'required' initializer
Answer:
Thanks to #SørenMortensen:
The issue with the private initialiser is that the MyNested class is accessible within MyClass, but the initialiser is only accessible within MyNested, and therefore is not as accessible as its enclosing type. And as #Hamish points out, the concept of a required initialiser is mutually exclusive with the concept of a private initialiser.
So it looks like it is not possible to have private required initializer, indeed. And in my case I can make MyNested class to be final and then make the initializer private not making it required.
Why would you want one?
The purpose of required means that one is forced to use this initialization when declaring this class. Like #Hamish said, setting it as private would just result in classes unable to see it and cannot declare it. If you want additional setup but don't want it to be accessible, why not just call a private func within a required init?

Swift constants: Struct or Enum

I'm not sure which of both are better to define constants. A struct or a enum. A struct will be copied every time i use it or not? When i think about a struct with static let constants it makes no sense that it will copied all the time, in my opinion. But if it won't copied then it doesn't matter what I take?
What advantages does the choice of a struct or enum?
Francescu says use structs.
Ray Wenderlich says use enums. But I lack the justification.
Both structs and enumerations work. As an example, both
struct PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
and
enum PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
work and define a static property PhysicalConstants.speedOfLight.
Re: A struct will be copied every time i use it or not?
Both struct and enum are value types so that would apply to enumerations as well. But that is irrelevant here
because you don't have to create a value at all:
Static properties (also called type properties) are properties of the type itself, not of an instance of that type.
Re: What advantages has the choice of a struct or enum?
As mentioned in the linked-to article:
The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace.
So for a structure,
let foo = PhysicalConstants()
creates a (useless) value of type PhysicalConstants, but
for a case-less enumeration it fails to compile:
let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
Here's a short answer: Do your constants need to be unique? Then use an enum, which enforces this.
Want to use several different constants to contain the same value (often useful for clarity)? Then use a struct, which allows this.
One difference between the two is that structs can be instantiated where as enums cannot. So in most scenarios where you just need to use constants, it's probably best to use enums to avoid confusion.
For example:
struct Constants {
static let someValue = "someValue"
}
let _ = Constants()
The above code would still be valid.
If we use an enum:
enum Constants {
static let someValue = "someValue"
}
let _ = Constants() // error
The above code will be invalid and therefor avoid confusion.
Using Xcode 7.3.1 and Swift 2.2
While I agree with Martin R, and the Ray Wenderlich style guide makes a good point that enums are better in almost all use cases due to it being a pure namespace, there is one place where using a struct trumps enums.
Switch statements
Let's start with the struct version:
struct StaticVars {
static let someString = "someString"
}
switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Using a struct, this will match and print out Matched StaticVars.someString.
Now lets consider the caseless enum version (by only changing the keyword struct to enum):
enum StaticVars {
static let someString = "someString"
}
switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
You'll notice that you get a compile time error in the switch statement on the case StaticVars.someString: line. The error is Enum case 'someString' not found in type 'String'.
There's a pseudo-workaround by converting the static property to a closure that returns the type instead.
So you would change it like this:
enum StaticVars {
static let someString = { return "someString" }
}
switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Note the need for parentheses in the case statement because it's now a function.
The downside is that now that we've made it a function, it gets executed every time it's invoked. So if it's just a simple primitive type like String or Int, this isn't so bad. It's essentially a computed property. If it's a constant that needs to be computed and you only want to compute it once, consider computing it into a different property and returning that already computed value in the closure.
You could also override the default initializer with a private one, and then you'll get the same kind of compile time error goodness as with the caseless enum.
struct StaticVars {
static let someString = "someString"
private init() {}
}
But with this, you'd want to put the declaration of the struct in its own file, because if you declared it in the same file as, say, a View Controller class, that class's file would still be able to accidentally instantiate a useless instance of StaticVars, but outside the class's file it would work as intended. But it's your call.
In the Combine framework, Apple has chosen to prefer enums for namespaces.
enum Publishers
A namespace for types that serve as publishers.
enum Subscribers
A namespace for types that serve as subscribers.
enum Subscriptions
A namespace for symbols related to subscriptions.

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
}// ^^^

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

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 }
}