This question already has answers here:
What is the difference between `let` and `var` in Swift?
(32 answers)
Closed 8 years ago.
I'm new to Swift programming, and I've met the var and let types. I know that let is a constant and I know what that means, but I never used a constant mainly because I didn't need to. So why should I use var instead of let, at what situation should I use it?
Rather than constant and variable, the correct terminology in swift is immutable and mutable.
You use let when you know that once you assign a value to a variable, it doesn't change - i.e. it is immutable. If you declare the id of a table view cell, most likely it won't change during its lifetime, so by declaring it as immutable there's no risk that you can mistakenly change it - the compiler will inform you about that.
Typical use cases:
A constant (the timeout of a timer, or the width of a fixed sized label, the max number of login attempts, etc.). In this scenario the constant is a replacement for the literal value spread over the code (think of #define)
the return value of a function used as input for another function
the intermediate result of an expression, to be used as input for another expression
a container for an unwrapped value in optional binding
the data returned by a REST API call, deserialized from JSON into a struct, which must be stored in a database
and a lot more. Every time I write var, I ask myself: can this variable change?. If the answer is no, I replace var with let. Sometimes I also use a more protective approach: I declare everything as immutable, then the compiler will let me know when I try to modify one of them, and for each case I can proceed accordingly.
Some considerations:
For reference types (classes), immutable means that once you assign an instance to the immutable variable, you cannot assign another instance to the same variable.
For value types (numbers, strings, arrays, dictionaries, structs, enums) immutable means that that once you assign a value, you cannot change the value itself. For simple data types (Int, Float, String) it means you cannot assign another value of the same type. For composite data types (structs, arrays, dictionaries) it means you cannot assign a new value (such as a new instance of a struct) and you cannot change any of their stored properties.
Also an immutable variable has a semantic meaning for the developer and whoever reading the code - it clearly states that the variable won't change.
Last, but maybe less important from a pure development point of view, immutables can be subject to optimizations by the compiler.
Generally speaking, mutable state is to avoid as much as possible.
Immutable values help in reasoning about code, because you can easily track them down and clearly identify the value from the start to the end.
Mutable variables, on the other hand, make difficult to follow your data flow, since anyone can modify them at any time. Especially when dealing with concurrent applications, reasoning about mutable state can quickly become an incredibly hard task.
So, as a design principle, try to use let whenever possible and if you need to modify an object, simply produce a new instance.
Whenever you need to use a var, perhaps because using it makes the code clearer, try to limit their scope as much as possible and not to expose any mutable state. As an example, if you declare a var inside a function, it's safe to do so as long as you don't expose that mutability to the caller, i.e. from the caller point of view, it must not matter whether you used a var or a val in the implementation.
In general, if you know a variable's value is not going to change, declare it as a constant. Immutable variables will make your code more readable as you know for sure a particular variable is never being changed. This might also be better for the compiler as it can take advantage of the fact that a variable is constant and perform some optimisations.
This doesn't only apply to Swift. Even in C when the value of a variable is not be changed after being initialised, it's good practise to make sure it's const.
So, the way you think about "I didn't need to" should change. You don't need a constant only for values like TIMEOUT etc. You should have a constant variable anywhere you know the value of a variable doesn't need to be changed after initialisation.
Note: This is more of a general "programming as a whole" answer and not specific to Swift. #Antonio's answer has more of a focus on Swift.
Related
I am working on a project that deals with lots of atomic operations. Till now I didn’t knew about atomic_load() and was only relying on assignment operator to get value of an atomic type and I haven’t seen an error except of so much of testing. Those atomic types are changed by multiple processes and threads as well by atomic_compare_exchange_strong_explicit(), so they will need an old value every time, and that’s where I always did oldValue = <Atomic_ type_variable> and it always works fine.
Is that just by chance? Should I prefer using atomic_load()?
foo = atomic_var is just a shortcut syntax for foo = atomic_load(&atomic_var);
Which itself is a shortcut for foo = atomic_load_explicit(&atomic_var, memory_order_seq_cst); That has a use-case when you want to use an ordering weaker than the default seq_cst.
The main reason for using atomic_load explicitly in your source code is probably to remind human readers that a variable or pointer is atomic. Or maybe as a part of a macro, using atomic_load(&(macro_input)) would create a compile-time error for a non-atomic pointer.
As a "generic" function, you can't take a normal function-pointer to it.
Its existence may be just to make it easier to write the language standard, and explain everything in terms of functions.
It's not the actual assignment that's key here, it's evaluating the atomic variable in an rvalue context (reading it's value as part of an expression, like you typically find on the right-hand side of an =). printf("%d\n", my_atomic_var); is also equivalent to atomic_load.
And BTW, the same thing holds for atomic_var = foo; being exactly the same as atomic_store_explicit with mo_seq_cst. Here it is assignment that's key.
Other kinds of lvalue references to an atomic variable are different, like read-modify-write atomic_var++ is equivalent to atomic_fetch_add.
Swift question with the goal of understanding the language better:
I understand the difference between a var and let
var are mutable
let are final
I'm assuming both of these are written to the stack. Once a variable is created the object class that it stores is set. Is it every possible to change this?
let myVar = String("Hello")
// myVar.dynamicType is String
myVar.delete
let myVar = Int(123)
myVar.dynamicType is Int
Is there a way to reallocate the memory for a variable? I want to use the same variable name to mean a different thing in a different section on the code.
Identifiers in Swift (both constant and mutable), as in most other static type-checked programming languages, have a scope (see the Wikipedia entry) that defines the extent of their validity. A scope could be the body of a function, a file, a module, or just the body of a for loop. In a language like Swift, you cannot reuse the same identifier for two different values or memory cells inside the same scope, but you can do it in two different scopes. So the answer to your question is: you cannot do it in the same scope, but you can do it in different scopes. Note, however that you are not using the same memory, just the same name associated to a different piece of memory (in case of var) or a different value (in case of let).
Actually you cannot delete neither the value associated to an identifier, neither the memory itself (as it seems that you think possible in your example). This is impossible in any language that has stack allocated entities, since the recovery from the stack is automatic at the end of the current block of code.
In swift a value in an immutable array can be changed but a value in an immutable dictionary can not be changed Why?
let imArray = ["Ram","Shyam","Bharat"]
imArray[2] = "Abhimanyu" // this change will be apply though it is immutable
EDIT: In Xcode 6 beta 3 notes, this is now changed. They now behave the same.
Array in Swift has been completely redesigned to have full value
semantics like Dictionary and String have always had in Swift. This
resolves various mutability problems – now a 'let' array is
completely immutable, and a 'var' array is completely mutable –
composes properly with Dictionary and String, and solves other deeper
problems. Value semantics may be surprising if you are used to
NSArray or C arrays: a copy of the array now produces a full and
independent copy of all of the elements using an efficient lazy copy
implementation. This is a major change for Array, and there are
still some performance issues to be addressed. Please see the Swift
Programming Language for more information. (17192555)
I talked to an Apple engineer regarding this in WWDC
For arrays, when you define it as a constant, this means the backing buffer is constant, and thus you can change the contents of the buffer, but not swap out the buffer or modify its length.
For dictionaries, it is completely immutable.
Of course, if you think it should behave differently, submit a ticket to them!
From Apple's Swift documentation, under Mutability of Collections...
Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you are allowed to set a new value for an existing index in the array. This enables Swift’s Array type to provide optimal performance for array operations when the size of an array is fixed.
In C# or php or other languages, there are 2 ways to pass a value to a function, pass it by value and pass it by referece.
Pass parameter by value make the value copied in the function, so this need a extra memory space although the memory space will be reclaimed after running outside the function.
But passing parameter by reference no need to copy a value, it's save the memory. From this perspective, can we say that using "pass by reference" is always better than "pass by value"?
Pass by reference and pass by value are semantically different and sometimes one is correct approach and sometimes the other one is. In many cases the task at hand already prescribes which approach is needed and in contexts where only one option is supported you often need to manually work around it (e.g., if you need a copy in Java you'll need to clone() the object).
In the context of generic functions the answer is rather the opposite way of your proposed preference: pass arguments of deduced type by value! The reason is that you can use something like std::ref() to obtain reference semantics but there is no way to get value semantics if the functions use reference semantics.
No.
There are tons of cases where you'd want to pass by value.
An example might be when you need both const Type& and Type&& overloads. Passing by value just handles both cases without having to duplicate any code:
void function(Object o) { do_something_with(std::move(o)); }
As opposed to:
void function(Object&& o) { do_something_with(std::move(o)); }
void function(const Object& o) { do_something_with(Object(o)); }
Of course there is much more to the subject, but since you're only asking for "is it always better?" I feel a single disproving example is enough. ;)
Edit: the question was originally tagged c++ hence my very specific answer.
Another, more language-agnostic example would be when you need to make a copy of your parameter because you don't want to modify the original object:
void function(int& val) { int v2 = val; modify(v2); use(v2); }
// vs
void function(int val) { modify(val); use(val); }
You get the idea...
Pass by reference requires copying a reference to the object. If that reference is comparable in cost to the object itself, then the benefit is illusory. Also, sometimes you need a copy of the object, and passing by value provides you one.
Also, there's a key error in the reasoning in the question. If passing by value, and there is no need to copy the value, nothing requires that the value actually be copied. Most languages have an "as-if" rule that states that the program only has to act as if the compiler did what you ask for. So if the copy can be avoided, the compiler is free to avoid it. If the copy can't be avoided, then you needed the copy.
I mean if there's some declarative way to prevent an object from changing any of it's members.
In the following example
class student(var name:String)
val s = new student("John")
"s" has been declared as a val, so it will always point to the same student.
But is there some way to prevent s.name from being changed by just declaring it like immutable???
Or the only solution is to declare everything as val, and manually force immutability?
No, it's not possible to declare something immutable. You have to enforce immutability yourself, by not allowing anyone to change it, that is remove all ways of modifying the class.
Someone can still modify it using reflection, but that's another story.
Scala doesn't enforce that, so there is no way to know. There is, however, an interesting compiler-plugin project named pusca (I guess it stands for Pure-Scala). Pure is defined there as not mutating a non-local variable and being side-effect free (e.g. not printing to the console)—so that calling a pure method repeatedly will always yield the same result (what is called referentially transparent).
I haven't tried out that plug-in myself, so I can't say if it's any stable or usable already.
There is no way that Scala could do this generally.
Consider the following hypothetical example:
class Student(var name : String, var course : Course)
def stuff(course : Course) {
magically_pure_val s = new Student("Fredzilla", course)
someFunctionOfStudent(s)
genericHigherOrderFunction(s, someFunctionOfStudent)
course.someMethod()
}
The pitfalls for any attempt to actually implement that magically_pure_val keyword are:
someFunctionOfStudent takes an arbitrary student, and isn't implemented in this compilation unit. It was written/compiled knowing that Student consists of two mutable fields. How do we know it doesn't actually mutate them?
genericHigherOrderFunction is even worse; it's going to take our Student and a function of Student, but it's written polymorphically. Whether or not it actually mutates s depends on what its other arguments are; determining that at compile time with full generality requires solving the Halting Problem.
Let's assume we could get around that (maybe we could set some secret flags that mean exceptions get raised if the s object is actually mutated, though personally I wouldn't find that good enough). What about that course field? Does course.someMethod() mutate it? That method call isn't invoked from s directly.
Worse than that, we only know that we'll have passed in an instance of Course or some subclass of Course. So even if we are able to analyze a particular implementation of Course and Course.someMethod and conclude that this is safe, someone can always add a new subclass of Course whose implementation of someMethod mutates the Course.
There's simply no way for the compiler to check that a given object cannot be mutated. The pusca plugin mentioned by 0__ appears to detect purity the same way Mercury does; by ensuring that every method is known from its signature to be either pure or impure, and by raising a compiler error if the implementation of anything declared to be pure does anything that could cause impurity (unless the programmer promises that the method is pure anyway).[1]
This is quite a different from simply declaring a value to be completely (and deeply) immutable and expecting the compiler to notice if any of the code that could touch it could mutate it. It's also not a perfect inference, just a conservative one
[1]The pusca README claims that it can infer impurity of methods whose last expression is a call to an impure method. I'm not quite sure how it can do this, as checking if that last expression is an impure call requires checking if it's calling a not-declared-impure method that should be declared impure by this rule, and the implementation might not be available to the compiler at that point (and indeed could be changed later even if it is). But all I've done is look at the README and think about it for a few minutes, so I might be missing something.