Why do I need to declare an optional value as nil explicitly in Struct - Swift - swift

Here's a quote from the docs:
If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.
If I do this with a class it works fine:
class MyClass {
var someProperty: String?
}
var myClass = MyClass()
myClass.someProperty // Shows nil
However, if I do this with a struct type, I get an error on initialization:
struct MyStruct {
var someProperty: String?
}
// ERROR
var myStruct = MyStruct()
Error:
Missing argument for parameter 'someProperty'
I can remedy this by declaring it nil explicitly like so:
struct MyStruct {
var someProperty: String? = nil
}
// Valid
var myStruct = MyStruct()
Question
Given the documentation, I would expect properties on any type that are set as optionals to be defaulted to nil. Is there a reason I have to declare it explicitly on a struct?
Why?
No good reason, like many of you, I'm just experimenting.

Both Classes and Structs need to have all property values set when they are initialized. This can be done either through explicit default values or by setting a value in the designated initializer.
However, Structs differ in the fact that they have an automatically generated memberwise initializer.
When you don't define a value for someProperty explicitly, your struct has one initializer only: the automatically generated memberwise one.
If you do provide a default value, you get two: one that takes no arguments, and one that takes a value for someProperty as an argument
From the docs:
All structures have an automatically-generated memberwise initializer,
which you can use to initialize the member properties of new structure
instances. Initial values for the properties of the new instance can
be passed to the memberwise initializer by name:
let vga = Resolution(width: 640, height: 480)
Unlike structures, class instances do not receive a default memberwise
initializer. Initializers are described in more detail in
Initialization.

I agree this is rather quirky (unless I'm also missing something). For structures with only optionals, it might be worth suggesting (via Apple bugreport) that in such cases, a default parameterless initialiser is also added by default?
Another remedy is
var myStruct = MyStruct(someProperty:nil)
However, if you had a lot of optional members, this becomes clumbsy.

I think this is an deliberate difference between structs and classes, which makes a bit of sense. For example when you have a struct, say a 3d point with three floats for XYZ. It doesn't make much sense to have a nil value for x or y or z. With a class on the other hand this is a very important feature. If you think about a downloader class, for example, that goes and downloads a text file and stores it in a property. It makes more sense for that property to be nil when the class is first initialized. Since apple has changed structs to be much more closely related to classes I think this is an important distinction. It's my opinion that setting the optional explicitly to nil is a bug.
My reasoning for this:
In the optional documentation all of the example are on classes.

Related

Difference between 'get' and 'get set' in Swift

I understand that 'get' is used to give instructions on value for the variable 'numberOfWheels' is acquired. However, I do not understand what 'get set' is supposed to achieve in the code below. Does it mean that value can be acquired from the class, enum, or struct AND can also be acquired by a parameter passed on?
protocol WheeledVehicle: Vehicle {
var numberOfWheels: Int { get }
var wheelSize: Double { get set }
}
This protocols requires conforming types (classes, structs or enums) to have two properties:
numberOfWheels, which must provide at least a getter. This means it's either a let property, a var property, or a computed property with at least a getter (the setter is optional).
wheelSize, which must provide a getter and a setter. This means it has to be either a var property, or a computer property with both a getter and a setter.

Swift static property initilizers are lazy why I could declared it as a constant

As far as I known (see reference A), Static property initilizers are lazy, and I found the following description by the office documents
You must always declare a lazy property as a variable (with the var
keyword) because its initial value might not be retrieved until after
instance initialization completes. Constant properties must always
have a value before initialization completes, and therefore cannot be
declared as lazy.
From the above information, I think I couldn't define the static property as a constant variable and I made a tryout, it turns out I can do that without triggering any error from the compiler.
Example:
class Person {
static let firstNaID = "First Name"
static let lastNaID = "Last Name"
}
Question: Is this a bug of the Swift 3.0.1 or I was wrong.
Reference A: Neuburg. M.2016. IOS 10 Programming Fundamental with Swift. P127
Thanks for your time and help
Neuburg M. is drawing a distinction between static properties and instance properties. You are pretending to ignore that distinction. But you cannot ignore it; they are totally different things, used for different purposes.
In this code:
class Person { // let's declare a static property
static let firstNaID = "First Name"
}
... firstNaID is already lazy. But now try to do this:
class Person { // let's declare an instance property
lazy let firstNaID : String = "First Name" // error
}
You can't; as things stand (up thru Swift 3.1), you have to say lazy var instead — and when you do, you get a lazy instance property.
Your static let declaration thus doesn't accomplish what lazy let wanted to accomplish, because a static property is not an instance property.
You are talking about type properties
Form the same chapter of the documentation
Type Properties
... Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use ...
Stored type properties can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.
NOTE
...
Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.

Why do I use Initializers in Swift?

I am trying to get my head around initializers in Swift. I kind of get what they do, but I dont get why I need them.
For example: (from apples documentation)
class NamedShape {
var numberOfSides = 0
var name: String
var sideLength: Double
init(name: String, sideLength: Double) {
self.name = name
self.sideLenght = sideLength
}
}
If init should set an initial value, shouldn't self.sideLength equals an actual value, instead of just "sideLength". Or do I need to create an init to take in arguments to a function?
I'm so confused but would really appreciate if someone could help me.
The main purposes of initialisers is to initialise non-Optional variables. Your class has three variables - numberOfSides, name and sideLength. You give numberOfSides an initial value of zero, so it is happy. However, name and sideLength do not have values, which is "illegal" for a non-Optional. Therefore they must be given values in an initialiser. For example, if you comment out one of the lines in the init, you will get a compilation error because that variable will now not be initialised. And you do this when you cannot logically determine initial values at compile time - you could argue this is the case with numberOfSides too, as there is no shape that has no sides.
Elsewhere in your code you might want to validate numberOfSides is at least 1. This could be achieved by having numberOfSides undefined at compile time, and passed in the init, whereby if it's not at least 1, your initialiser could return nil (which would mean using an failable initialiser - init?).
Note that in your case, the name passed in the initialiser, is not the same as the name variable in the class. This is why you have to do:
self.name = name
To copy the name value passed in the initialiser into the variable in the class.

Why doesn't Swift allow setting value of an optional constant after object initialization?

The code below creates a compile error saying "error: return from initializer without initializing all stored properties ('self.response' not initialized)"
class Question {
let text: String
let response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
I want to make "response" constant and by the time I initialize, response will be unknown. Besides "return from initializer without initializing all stored properties", why do I have to make it "var"?
Because Swift tries to make you implement safe code, and having uninitialized stored properties is really not safe, because you or a client of your class may use that constant before it is properly set and the result will be undefined. This is a cause of a lot of bugs that may not be immediately caught.
Moreover, because an optional constant stored property is initialized as having a nil value, if you were able to change its value after initialization you would violate the "constantness" of your constant. That is why you need to declare it as a var.
Optional variables / properties are automatically set to nil by definition if no initial value is provided in the declaration line.
An optional constant is stuck to nil which makes no sense...
Therefore the compiler doesn't let you declare an optional constant this way.

Class instance variable initialization order?

Currently, I am seeing something strange behavior.
class DataManager1
{
let THE_ID = "SOME_ID_STRING"
let _con1 = CKContainer(identifier: THE_ID) // error
// error: 'DataManager1.Type' does not have a member named 'THE_ID'
}
class DataManager2
{
let THE_ID = "SOME_ID_STRING"
let _con1:CKContainer?
init()
{
_con1 = CKContainer(identifier: THE_ID) // no error.
}
}
In C++ we have a defined initialization order between instance member variables. I expected something similar, but actually I couldn't find a mention for that form the manual.
Does Swift has a defined initialization order of properties? If it does, what is the rule, and where can I find the rule?
This is due to the fact that you're using a Closure (a Function is just a special case of Closure that is unnamed) to initialize the _con1 property with a default value.
From the Apple provided iBook:
If you use a closure to initialize a property, remember that the rest
of the instance has not yet been initialized at the point that the
closure is executed. This means that you cannot access any other
property values from within your closure, even if those properties
have default values. You also cannot use the implicit self property,
or call any of the instance’s methods.
Even though the note above refers specifically to closures, it seems that trying to set the default value for a property to be that of another property directly also does not work.