let declarations require an initializer expression - ios

I'm reading The Swift Programming Language, in the Simple Values section
“Use let to make a constant and var to make a variable. The value of a
constant doesn’t need to be known at compile time, but you must assign
it a value exactly once”
So I think I can do this
let aConstant:Int
aConstant = 5
But I get let declarations require an initializer expression !!
Why is that ? What does they mean by "The value of a constant doesn’t need to be known at compile time" ?

From the Swift Language Reference:
When a constant is declared at global scope, it must be initialized with a value.
You can only defer initialization of a constant in classes/structs, where you can choose to initialize it in the initializer of the class/struct.
The meaning of "The value of a constant doesn’t need to be known at compile time" refers to the value of the constant. In C/Objective-C a global constant needs to be assigned a value that can be computed by the compiler (usually a literal like 10 or #"Hello"). The following would not be allowed in Objective-C:
static const int foo = 10; // OK
static const int bar = calculate_bar(); // Error: Initializer element is not a compile-time constant
In Swift you don't have this restriction:
let foo = 10 // OK
let bar = calculateBar(); // OK
Edit:
The following statement in the original answer is not correct:
You can only defer initialization of a constant in classes/structs, where you can choose to initialize it in the initializer of the class/struct.
The only place where you cannot defer is in global scope (i.e. top level let expressions). While it's true that you can defer initialization in a class/struct, that's not the only place. The following is also legal for example:
func foo() {
let bar: Int
bar = 1
}

A constant does not need to be known at compile, but it must have a value after initialization:
class MyClass: NSObject {
let aConstant: Integer; // no value
init() {
aConstant = 4; // must have a value before calling super
super.init();
}
}
This allows you to set the constant to a value after it is declared and potentially unknown at compile time.

the let keyword, by definition, defines a constant.
Thus, you can't modify it once its been set.
Since thats the case, they need to be initialized when they are declared!
The solution here is to do either:
let aConstant = 5
or change it to a var
var aNonConstant:Int
aNonConstant = 5

Answer for Swift 2:
You can write constants as follows:
let aConstant:Int
aConstant = 5
Setting the type this way means: "This will be constant and it will have value when you need it". Notice that you cannot use the constant before setting value to it, there is a compile time error:
Constant 'aConstant' used before being initialized
Furthermore you can set value to aConstant only once. If you try to set value for second time, there is compile time error:
Immutable value 'aConstant' may only be initialized once
Anyway you cannot do this for global constants, there is compile time error:
Global 'let' declaration requires an initializer expression

Related

Variable name conflicts with function name leads to "Variable used within its own initial value"

Having this function
private func date(from string: String) {
// Do thing with string
}
when calling it with
let date = date(from: "11:30")
it produces the following error
Variable used within its own initial value
obviously changing the code to
let anythingButDate = date(from: "11:30")
will make the error go away but I am trying to understand why there is a conflict between variable name and method name in the first place.
UPDATE:
To be more precise - I understand that the compiler is having issues with giving the variable and the function the same name but I am curious why can't it distinguish that one is a variable name and the other is a function name.
There is no big distinction between functions and variables because even a variable can hold a function or closure. What you have is a conflict of identifiers.
You can use
date = self.date(...)
to make the intent clear.
Your function is called date, even though it has a parameter it will conflict if you´re trying to call a variable the same name in this case date. What happens is that the compiler tries to use the declared constant date to assign its own initial value.
When you use anythingButDate then it´s fine because your function is not called that and you don´t have any other function called anythingButDate.
let date = date(from: "11:30") // will not work
let datex = date(from: "11:30") // will work
let anythingButDate = date(from: "11:30") // will work

Difference between property and class instance swift

I am new to swift programming, and i have a question as follows:
I have a class named Weather
class Weather {
}
then i define 2 things:
var currentWeather1 = Weather()
var currentWeather2: Weather!
Are they different syntax or the same meaning? What are they actually created in memory with these 2 statements?
var currentWeather1 = Weather()
This declares a variable of type Weather and assigns a new instance of Weather to it. The syntax Weather() creates an instance and runs its initialiser. The compiler infers the type of currentWeather1 to be Weather. The statement above is exactly equivalent to
var currentWeather1: Weather = Weather()
The other statement:
var currentWeather2: Weather!
declares an implicit optional variable. This variable is of optional type i.e. it's type is Optional<Weather>. This means that it needs to be unwrapped if you want to get at the value. However, the ! means that the compiler will put in the unwrapping code for you. A normal optional would look like this:
var currentWeather3: Weather?
but when you need to use it, you have to unwrap it e.g.
if let foo = currentWeather3
{
// foo is the unwrapped weather
}
let string = currentWeather3?.description // string is an optional String
let string2 = currentWeather3!.description // string2 is a String
The last example with the ! is a forced unwrapping. If currentWeather3 is nil, when the line executes, the program will crash. The declaration of currentWeather2 means the compiler treats every mention of currentWeather2 as if it has an implicit ! after it.
The simple answer is
var currentWeather2: Weather!
Declares a variable by creating a references of the Weather in system table. But does not allocate any memory for the variable
var currentWeather1 = Weather()
Weather object is created by allocating memory and the location of the variable is assigned to the system table entry of age.
var currentWeather2: Weather!
The above statement does not allocate memory for an instance of Weather, it only allocates a stack variable currentWeather2. The reference pointers only are allocated on stack. The time it hits the currentWeather2 = Weather(), it allocates on "heap".
To access class properties & methods refer directly from the class name rather than with an instance of the class.
it will be helpful to understand more,it's in C# but concept is same
https://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types

Why latest Swift version always says variable is not initialized before use

Take an example
Class A {
var a : Int
override func viewDidLoad() {
super.viewDidLoad()
a=0
}
when it says variable is not initialized, even when i already declared in class first.
viewDidLoad is not the equivalent of init
I suggest you either use optionals:
var a:Int?
or you can initialize your variable directly in its declaration
var a:Int = 0
Last but not least, if you want to initialize any other way, do it in the init
override init() {
super.init()
a = 0
}
when you declare property in the class with Int it indicates it has no initializers. either give value at initialize time var a : Int = 0
or give value using init block which is use initialize the property of class. or you can also give declare as optional with ? var x : Int?
override init() {
super.init()
a = 0
}
Swift performs Two phase initialization :
Two-Phase Initialization
Class initialization in Swift is a two-phase
process. In the first phase, each stored property is assigned an
initial value by the class that introduced it. Once the initial state
for every stored property has been determined, the second phase
begins, and each class is given the opportunity to customize its
stored properties further before the new instance is considered ready
for use.”
Basically, this means that a property is not ready for use till it is provided an initial value.
In Objective-C, this was handled internally as the properties were set nil or 0 (depending on the data type) until initialized.
This behavior is provided by Optionals in Swift.
“You use optionals in situations where a value may be absent. An
optional says:
There is a value, and it equals x or
There isn’t a value at all”
As mentioned by other answers, you can declare an optional using a "?"
eg: var a : Int?
For details refer : The Swift Programming Language (Swift 2.2).

How is 'let' implemented?

I pulled this example straight from this Apple page
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
and if you assign an instance of this structure to a constant,
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
it says we can't change its property values even if it is declared as 'var'
This makes me wonder how let is implemented? I hope any assignments to it can be detected at compile time and show compile error. But in the above case, why does it apply to every property of the structure, regardless of how it is defined?
I tried to search for this, finding it very difficult to search with keyword 'let' as it is quite common term.
Can anyone help me to understand this?
It's because a struct is a value type. This means it cannot be mutated in place.
Thus, if we have a variable rangeOfFourItems that is a FixedLengthRange struct instance, and we want to set rangeOfFourItems.firstValue, we are actually ripping the struct instance right out of the rangeOfFourItems storage and replacing it with another struct instance with a different firstValue.
To see that this is true, declare rangeOfFourItems with var and attach a setter observer to it, and then change rangeOfFourItems.firstValue:
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfFourItems = FixedLengthRange(firstValue:1, length:4) {
didSet {
print("Hey, you set me!")
}
}
rangeOfFourItems.firstValue = 2 // Hey, you set me!
This shows that merely setting the property of this struct instance actually sets the struct variable itself.
But in your code, we cannot do that, because rangeOfFourItems prevents this implicit assignment - it is declared with let, meaning it must remain a constant. Thus, setting rangeOfFourItems.firstValue is prevented at compiler level.
(If FixedLengthRange were a class instead of a struct, it would be a reference type, and would be mutable in place, and setting rangeOfFourItems.firstValue would be legal even if rangeOfFourItems was declared with let.)

Declaring a constant in swift

As I read the swift guide it says: The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once.
I tried in REPL but without any luck:
let aConst;
aConst=23;
So how to declare a constant without setting initial value?
Example
let myConstant = getSomeValueFromMethod()
This is what it means that the value doesn't have to be known at compile time...
You can't declare a constant, then assign it at the global scope. If you have to do something like this, use a variable instead. When a constant is declared at global scope, it must be initialized with a value.
Docs
You can't just declare a constant without assigning it some sort of value. The compiler needs to know that the constant will have some sort of value. Consider the following example where a constant "isTablet" is computed based on variables that aren't known until runtime.
let isTablet = {
if (UIDevice.currentDevice().userInterfaceIdiom == .Pad) {
return true
} else {
return false
}
}()
Another example beside Suthan's:
var someVar: NSString
...
someVar = "Some String"
let someUnknownConstant = someVar

Resources