Differences Objective-C const and let Swift in terms of run and compile time - swift

I am trying to figure out difference between Objective-C and Swift constant. I just read a tutorial document
//Objective-C
const int number = 0;
//Swift
let number = 0
"A const is a variable initialized at compile time with a value or an expression that must be resolved at compilation time.
An immutable created with let is a constant determined at runtime. You can initialize it with a static or a dynamic expression. This allows a declaration such as:
let higherNumber = number + 5
Note that you can only assign its value once."
Can someone explain these phrases and deep little dive into to explain why let constant determined at runtime ? I was thinking let is constant and never change.

Let means once assigned the value can’t be changed. The compiler will enforce that. An expression like “let now=Date()” can’t be determined at compile time but at compile time you can disallow reassigning to “now”.. “let pi = 3.141” can be determined at compile time, enabling optimisations and that is like C’s const
Note for reference types (classes) let means the assigned object will continue to be the same object, it doesn’t mean the object itself can’t or doesn’t change.

Related

What's the difference between var and let in Zephir

I read the Zephir's documentation (https://docs.zephir-lang.com/0.12/en/types) and I'm not sure I understand the difference between var and let in Zephir. My first thought was that maybe var only declares a variable and if you want to assign it to something, you have to use let. But then I saw the following lines in the documentation:
var a = false, b = true;
var number = 5.0, b = 0.014;
and I'm quite confused now.
Per the docs:
Variables are, by default, immutable. This means that Zephir expects
that most variables will stay unchanged. Variables that maintain their
initial value can be optimized down by the compiler to static
constants. When the variable value needs to be changed, the keyword
let must be used.
In other words, your assumption seems right. The reason the sample you posted uses var is because those are initial assignments as opposed to reassignments. Immutable, in that context, means that Zephir expects variables to maintain their original values.

Why is constant instance of a value type can NOT change its properties while constant instance of a reference type can?

I'm new to Swift and is trying to learn the concept of Property. I saw the statements and code below from "swift programming language 2.1".
struct FixedLengthRange {
var firstvalue: Int
let length: Int
}
let rangeOfFourItems = FixedLengthRange(firstvalue: 0, length: 4)
rangeOfFourItems.firstvalue = 8 //error: cannot assign to property: rangeOfFourItems is a "let" constant
And the book provided the following explanation for the error:
This behavior is due to structures being value types. When an instance
of a value type is marked as a constant, so are all of its properties.
The same is not true for classes, which are reference types. If you
assign an instance of a reference type to a constant, you can still
change that instance’s variable properties.
Why is constant instance of a value type can NOT change its properties while constant instance of a reference type can? What is the reason behind it? The book did say how but failed to explain why. I think it is good practice to understand the reasons behind how things the way they are. Could someone please kindly explain it to me?
why is constant instance of a value type can NOT change its properties
Because value type is treated as an indivisible unit: it gets copied on assignment, passing it as a parameter behaves like a copy, and so using const-ness locks down the entire struct. In a sense, rangeOfFourItems variable represents the structure itself, not a pointer or a reference to it.
while constant instance of a reference type can?
This is not entirely correct to say that declaring a const variable of reference type makes the instance constant as well. Only the reference is constant, not the instance.
If you think about it, that is the only way this could be meaningfully implemented, because multiple variables can reference the same by-reference instance. If one of these variables is constant and the other one is not constant, assigning a non-const reference to a constant variable could not possibly lock down the referenced object, which would lock out the non-const reference as well:
var a = ByRefType()
let b = a; // b is a constant reference to the same instance as "a"
a.property = newValue; // Prohibiting this assignment would be inconsistent
Of course the constant variable itself (e.g. b above) could not be re-assigned, unlike the non-constant variable a.

Swift: confused about nullable/optional types

I'm new to Swift and iOS coding and have been working on writing my first app. While my programming background is pretty significant, I come from a Python and C# background where pretty much anything can be None or null and it's up to the user to check at runtime for a null. I'm finding this whole concept of "nullable vs. non-nullable types" or "optional types" in Swift to be confusing.
I understand that the core concept is that a variable declared as a type like myObject cannot be set to nil. However, if I define it as type myObject? then the value can be set to nil.
The problem is that, when I look at my code designs, it feels like everything will have to be "nullable" in my code. It feels like this either means I'm not thinking correctly with how my code should run, or that I'm missing some crucial piece of understanding.
Let's take the simplest example of something I am confused about. Suppose I have two classes - one that stores and manages some sort of data, and another that provides access to that data. (An example of this might be something like a database connection, or a file handle, or something similar.) Let's call the class containing data myData and the class that works with that data myObject.
myObject will need a class-level reference to myData because many of its methods depend on a local reference to the class. So, the first thing the constructor does is to generate a data connection and then store it in the local variable dataConnection. The variable needs to be defined at the class level so other methods can access it, but it will be assigned to in the constructor. Failure to obtain the connection will result in some sort of exception that will interfere with the very creation of the class.
I know that Swift has two ways to define a variable: var and let, with let being analogous to some languages' const directive. Since the data connection will persist throughout the entire life of the class, let seems an obvious choice. However, I do not know how to define a class-level variable via let which will be assigned at runtime. Therefore, I use something like
var dataConnection: myData?
in the class outside any functions.
But now I have to deal with the nullable data type, and do explicit unwrapping every time I use it anywhere. It is frustrating to say the least and quite confusing.
func dealWithData() {
self.dataConnection.someFunctionToGetData() <- results in an unwrapping error.
self.dataConnection!.someFunctionToGetData() <- works.
let someOtherObjectUsingData: otherObject = self.getOtherObject() <- may result in error unless type includes ?
someOtherObjectUsingData.someMethod(self.dataConnection) <- unwrap error if type included ?
var myData = self.dataConnection!
someOtherObjectUsingData.someMethod(myData) <- works
}
func somethingNeedingDataObject(dataObject: myData?) {
// now have to explicitly unwrap
let myDataUnwrapped = myData!
...
}
This just seems to be an extremely verbose way to deal with the issue. If an object is nil, won't the explicit unwrap in and of itself cause a runtime error (which could be caught and handled)? This tends to be a nightmare when stringing things together. I've had to do something like:
self.dataConnection!.somethingReturningAnObject!.thatObjectsVariable!.someMethod()
var myData? = self.dataConnection
var anotherObject? = myData!.somethingReturningAnObject
...
The way I'm used to doing this is that you simply define a variable, and if it is set to null and you try to do something with it, an exception (that you can catch and handle) is thrown. Is this simply not the way things work anymore in Swift? This has confused me sufficiently that just about every time I try to compile an app, I get tons of errors about this (and I just let Xcode fix them). But this can't be the best way to deal with it.
Do I have to consistently deal with wrapping and unwrapping variables - even those which are expected to never be null in the first place but simply can't be assigned at compile time?
However, I do not know how to define a class-level variable via let which will be assigned at runtime.
This part is easy. Just use let instead of var. With Swift 1.2 and later, you can delay the actual assignment of a let. The compiler is smart enough to do flow analysis and make sure it's assigned once, and only once, in all paths. So in the case of a class-wide let, the assignment can also happen in the constructor.
But now I have to deal with the nullable data type, and do explicit unwrapping every time I use it anywhere.
But this is what implicitly unwrapped Optionals are for. For example, StoryBoard defines all #IBOutlets as implicitly unwrapped, because the semantics are very clear: upon entrance to viewDidLoad() and everywhere after, unwrapping is safe. If you can prove clear semantics to yourself, you can do the same.
So you have roughly 4 choices:
A) declare at class level as implicitly unwrapped:
let dataConnection: MyData!
And be forced to initialize it in the constructor:
init() {
let whateverObj = someInitialCalculation()
dataConnection = whateverObj.someWayOfGettingTheConnection()
}
And from then on you don't need the '!'; it should be clear that implicit unwrap is always safe.
B) Initialize it right in its declaration if its initialization is reliable and sensible at that point, allowing you to forgo the entire concept of Optionals:
let dataConnection = SomeClass.someStaticMethod()
C) Declare at class level as a var, as implicit optional:
var dataConnection: MyData!
You won't have to init it in the constructor; let it be nil until its value can/should be computed. You still need some flow analysis to prove after a certain point, as in the case of #IBOutlets, accessing it will always be valid
D) The most 'unpredictable' case. Declare it as an explicit optional, because throughout the lifecycle of the class, the data connection will come and go:
var dataConnection: MyData?
func someMethodThatHandlesData() {
if let dC = dataConnection {
dc.handleSomeData()
}
else {
alert("Sorry, no data connection at the moment. Try again later.")
}
}
I think you're imagining that Swift always forces you down path D).
As far as your spaghetti-string code, you want to look into Optional Chaining, and only need to check the end result for nil.

Variable 'xxx' was never mutated, consider changing to 'let'

Updated to xcode7-beta I run across a new kind of warning. Here is my code
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
if let layoutInfo = self.layoutInfo {
attributes?.append(layoutInfo)
}
return attributes
}
the warning message is
Variable 'attributes' was never mutated, consider changing to 'let' constant
Why does xcode say Variable 'attributes' was never mutated?
Question Update
the warning is gone when I change my code to this
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect)
if let layoutInfo = self.layoutInfo {
attributes!.append(layoutInfo)
}
return attributes
}
so forced unwrapping can take it away. But it might not be a good thing right?
They talked about this in the WWDC videos and the release notes.
It has always been the case that you get much, much better performance (faster speed, smaller space) if you use let instead of var whenever you can. This tells the compiler that this thing is a constant, not a variable, and that fact allows the compiler to optimize all kinds of things away.
But the compiler can't do that unless you do use let whenever you can. It won't change a var to a let for you.
Therefore, in Swift 2, the compiler does a smarter analysis at build time and warns you if you are using var where you could have used let. Eventually this feature will work properly, at which point you should take the compiler's advice!
This has been driving me crazy too. Whenever I have a class and I change member properties, it still tells me that I should make the variable a constant. For instance:
class X {
var name = ""
}
var xInstance = X()
xInstance.name = "my name"
Near as I can figure, the compiler is correct. xInstance is a constant. It is assigned the pointer to the X instance during its initialization and is never assigned another value. So xInstance is constant. The class that it points to is not constant.
This is more obvious in a language like C or C++ but when you realize that all class instances are really pointers to heap backed classes, this makes sense.
For those who understand C++
xInstance is equivalent to:
X *xInstance
making it a let instead means that it changes to:
X * const xInstance
I think most people would intuitively think that the swift declaration would be equivalent to
X const * xInstance
By declaring a constant with let, you ensure that it can never be changed. This is good for making sure that you don't accidentally change it later, and it (in theory) can help the optimizer generate faster code.
If you declare a variable with var, and you don't intend to change it or call mutating methods on it, using let instead helps you enforce that contract.
You have created that object as var object but value of that object not changing then after better to make it let. That's it.
As per Apple Developer Guidelines, create var object if value of that object is going to change else create let variable. Best practise
Your code implies that attributes could be mutated if self.layoutInfo is non nil
Perhaps the warning is saying that no path leads to self.layoutInfo being non nil and hence attributes has no need of being a var.
Examine what conditions if any can lead to self.layoutInfo having data
Why this warning?
Because in Swift "let" means "value is constant" and allows compiler to do some optimizations, hence "let" is faster than "var",
And since "Swift 2", the compiler warns if we use "var" wherever it detects that we could use "let" instead.
Class vs Struct
However, in Swift the "class" is a reference-type (just like in Java), meaning the "value" is just "a reference and/or pointer to actual data".
Even if we use "let" with "class", the "data" pointed is never constant (and is always mutable).
So, if changing the "data" is a big thing and should not happen unnoticed, consider using struct.
In Swift "struct" is a value-type, and unless it's defined with "var" (or "inout" in "func" parameters), any mutation to the "data" it holds should cause compile error.
Basically same as const keyword available in C and C++ languages, but in C++ we don't need to migrate from "class" to a complete different type, jsut to have mutability sensitive class.
That's a plus for C++, but it fades to nothing, once we see the other C++ overcomplications.

correct declaration of variables in swift

Hi I'm new to swift language, first of all I don't know if this is a permitable topic I'm creating but I need to understand this and couldn't find any information on the web for this
in swift I realized there's a couple of ways for declaring a variable and it's type. but I don't know the differences and don't know where to use which..
correct me If I am wrong..
to begin with: when
var anything = "When I do it like this my anything variable becomes type of string"
but if I type
var anything = 12 //it's type Int
and so on.. apart from this I could also declare these variables as
var anything:Int
or
var anything:String
so far I'm good with this but what is the difference of declaring a global variable as
var anything:String
or
var anything:String = String()
how do I decide to use which and where? thank you
I'll start backwards. What is the difference between
var anything:String and var anything:String = String()
The first one declares a variable called anything of type String and the second initializes it by calling String's constructor. In the first case you will have to tell Swift's compiler what to expect from this variable - will it have a value or it will be nil. So the best thing to do if you don't know this is to declare it as optional:
var anything:String?
About the types that you initialize like this var anything = 12, Swift determines the type by the context, in this case it is an Int.
Swift types can be inferred (determined from the context). In
var anything: Int = 12
Int is redundant as it can be inferred form context (Int is default for integer literals). However sometimes you need more specific like Int8. You can then explicitly declare the type or use initialiser to infer the type type:
var anything: Int8 = 12
or
var anything = Int8(12)
Personally I used type inferring whenever I can and haven't run into any problems yet.
Your question is very basic, but I understand the trouble of learning a new language and that you need help. It is the standard learning curve.
Swift uses a technique called type inference. It can determine the type of a variable from the initial value.
var v = 8
automatically make v an Int.
var v:Int = 8
does the same
You can always use inferred types. Try to make your code readable and if type-inference improves the readability, then use it.
If you need more context to be able to understand your code 2 weeks after writing it, use explicitly declared types.
When you declare variables without an initial value you always have to declare the type explicitly. In this case, the compiler does not have any chance to guess the type.