I'm learning Swift and I'm reading The Swift Programming Language from Apple. I don't have any Objective-C background (only PHP, JavaScript, and others, but not Objective-C).
On page 24-25 I see this code:
//...Class definition stuff...
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
//...Class continues...
This part is not specified in the book, and I can't get what those are for.
What are get and set?
The getting and setting of variables within classes refers to either retrieving ("getting") or altering ("setting") their contents.
Consider a variable members of a class family. Naturally, this variable would need to be an integer, since a family can never consist of two point something people.
So you would probably go ahead by defining the members variable like this:
class family {
var members: Int
}
This, however, will give people using this class the possibility to set the number of family members to something like 0 or 1. And since there is no such thing as a family of 1 or 0, this is quite unfortunate.
This is where the getters and setters come in. This way you can decide for yourself how variables can be altered and what values they can receive, as well as deciding what content they return.
Returning to our family class, let's make sure nobody can set the members value to anything less than 2:
class family {
var _members: Int = 2
var members: Int {
get {
return _members
}
set (newVal) {
if newVal >= 2 {
_members = newVal
} else {
println('error: cannot have family with less than 2 members')
}
}
}
}
Now we can access the members variable as before, by typing instanceOfFamily.members, and thanks to the setter function, we can also set it's value as before, by typing, for example: instanceOfFamily.members = 3. What has changed, however, is the fact that we cannot set this variable to anything smaller than 2 anymore.
Note the introduction of the _members variable, which is the actual variable to store the value that we set through the members setter function. The original members has now become a computed property, meaning that it only acts as an interface to deal with our actual variable.
A simple question should be followed by a short, simple and clear answer.
When we are getting a value of the property it fires its get{} part.
When we are setting a value to the property it fires its set{} part.
PS. When setting a value to the property, Swift automatically creates a constant named "newValue" = a value we are setting. After a constant "newValue" becomes accessible in the property's set{} part.
Example:
var A:Int = 0
var B:Int = 0
var C:Int {
get {return 1}
set {print("Recived new value", newValue, " and stored into 'B' ")
B = newValue
}
}
// When we are getting a value of C it fires get{} part of C property
A = C
A // Now A = 1
// When we are setting a value to C it fires set{} part of C property
C = 2
B // Now B = 2
You should look at Computed Properties.
In your code sample, perimeter is a property not backed up by a class variable. Instead its value is computed using the get method and stored via the set method - usually referred to as getter and setter.
When you use that property like this:
var cp = myClass.perimeter
you are invoking the code contained in the get code block, and when you use it like this:
myClass.perimeter = 5.0
You are invoking the code contained in the set code block, where newValue is automatically filled with the value provided at the right of the assignment operator.
Computed properties can be read/write if both a getter and a setter are specified, or read-only if the getter only is specified.
A variable declares and is called like this in a class:
class X {
var x: Int = 3
}
var y = X()
print("value of x is: ", y.x)
//value of x is: 3
Now you want the program to make the default value of x more than or equal to 3. Now take the hypothetical case if x is less than 3: your program will fail.
So, you want people to either put in 3 or more than 3. Swift got it easy for you and it is important to understand this bit - it is an advanced way of dating the variable value, because they will extensively use it in iOS development. Now let's see how get and set will be used here.
class X {
var _x: Int = 3
var x: Int {
get {
return _x
}
set(newVal) { // Set always take one argument
if newVal >= 3 {
_x = newVal // Updating _x with the input value by the user
print("new value is: ", _x)
}
else {
print("error must be greater than 3")
}
}
}
}
let y = X()
y.x = 1
print(y.x) // The error must be greater than 3
y.x = 8 // // The new value is: 8
If you still have doubts, just remember the use of get and set is to update any variable the way we want it to be updated. get and set will give you better control to rule your logic. It is a powerful tool, hence not easily understandable.
Related
I know that swift will optimize to copy on write for arrays but will it do this for all structs? For example:
struct Point {
var x:Float = 0
}
var p1 = Point()
var p2 = p1 //p1 and p2 share the same data under the hood
p2.x += 1 //p2 now has its own copy of the data
Array is implemented with copy-on-write behaviour – you'll get it regardless of any compiler optimisations (although of course, optimisations can decrease the number of cases where a copy needs to happen).
At a basic level, Array is just a structure that holds a reference to a heap-allocated buffer containing the elements – therefore multiple Array instances can reference the same buffer. When you come to mutate a given array instance, the implementation will check if the buffer is uniquely referenced, and if so, mutate it directly. Otherwise, the array will perform a copy of the underlying buffer in order to preserve value semantics.
However, with your Point structure – you're not implementing copy-on-write at a language level. Of course, as #Alexander says, this doesn't stop the compiler from performing all sorts of optimisations to minimise the cost of copying whole structures about. These optimisations needn't follow the exact behaviour of copy-on-write though – the compiler is simply free to do whatever it wishes, as long as the program runs according to the language specification.
In your specific example, both p1 and p2 are global, therefore the compiler needs to make them distinct instances, as other .swift files in the same module have access to them (although this could potentially be optimised away with whole-module optimisation). However, the compiler still doesn't need to copy the instances – it can just evaluate the floating-point addition at compile-time and initialise one of the globals with 0.0, and the other with 1.0.
And if they were local variables in a function, for example:
struct Point {
var x: Float = 0
}
func foo() {
var p1 = Point()
var p2 = p1
p2.x += 1
print(p2.x)
}
foo()
The compiler doesn't even have to create two Point instances to begin with – it can just create a single floating-point local variable initialised to 1.0, and print that.
Regarding passing value types as function arguments, for large enough types and (in the case of structures) functions that utilise enough of their properties, the compiler can pass them by reference rather than copying. The callee can then make a copy of them only if needed, such as when needing to work with a mutable copy.
In other cases where structures are passed by value, it's also possible for the compiler to specialise functions in order to only copy across the properties that the function needs.
For the following code:
struct Point {
var x: Float = 0
var y: Float = 1
}
func foo(p: Point) {
print(p.x)
}
var p1 = Point()
foo(p: p1)
Assuming foo(p:) isn't inlined by the compiler (it will in this example, but once its implementation reaches a certain size, the compiler won't think it worth it) – the compiler can specialise the function as:
func foo(px: Float) {
print(px)
}
foo(px: 0)
It only passes the value of Point's x property into the function, thereby saving the cost of copying the y property.
So the compiler will do whatever it can in order to reduce the copying of value types. But with so many various optimisations in different circumstances, you cannot simply boil the optimised behaviour of arbitrary value types down to just copy-on-write.
Swift Copy On Write(COW)
Make a copy only when it is necessary(e.g. when we change/write).
By default Value Type[About] does not support COW(Copy on Write) mechanism. But some of system structures like Collections(Array, Dictionary, Set) support it
Print address
// Print memory address
func address(_ object: UnsafeRawPointer) -> String {
let address = Int(bitPattern: object)
return NSString(format: "%p", address) as String
}
Value type default behaviour
struct A {
var value: Int = 0
}
//Default behavior(COW is not used)
var a1 = A()
var a2 = a1
//different addresses
print(address(&a1)) //0x7ffee48f24a8
print(address(&a2)) //0x7ffee48f24a0
//COW for a2 is not used
a2.value = 1
print(address(&a2)) //0x7ffee48f24a0
Value type with COW (Collection)
//collection(COW is realized)
var collection1 = [A()]
var collection2 = collection1
//same addresses
print(address(&collection1)) //0x600000c2c0e0
print(address(&collection2)) //0x600000c2c0e0
//COW for collection2 is used
collection2.append(A())
print(address(&collection2)) //0x600000c2c440
Use COW semantics for large values to minimise copying data every time. There are two common ways:
use a wrapper with value type which support COW.
use a wrapper which has a reference to heap where we can save large data. The point is:
we are able to create multiple copies of lite wrapper which will be pointed to the same large data in a heap
when we try to modify(write) a new reference with a copy of large data will be created - COW in action. AnyObject.isKnownUniquelyReferenced() which can say if there is a
single reference to this object
struct Box<T> {
fileprivate var ref: Ref<T>
init(value: T) {
self.ref = Ref(value: value)
}
var value: T {
get {
return ref.value
}
set {
//it is true when there is only one(single) reference to this object
//that is why it is safe to update,
//if not - new reference to heap is created with a copy of value
if (isKnownUniquelyReferenced(&self.ref)) {
self.ref.value = newValue
} else {
self.ref = Ref(value: newValue)
}
}
}
final class Ref<T> {
var value: T
init(value: T) {
self.value = value
}
}
}
let value = 0
var box1 = Box(value: value)
var box2 = box1
//same addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000ac2490
box2.value = 1
print(box1.value) //0
print(box2.value) //1
//COW in action
//different addresses
print(address(&box1.ref.value)) //0x600000ac2490
print(address(&box2.ref.value)) //0x600000a9dd30
For example:
var dogName : String {
return "Buster"
}
VS..
let dogName = "Buster"
Let's say we're declaring each of these at the top level of a class as instance properties. Are these just two ways of doing the same thing? If not, what's the point of having a read-only variable?
Thanks
Let me try to sum up what the other answers are saying while also adding missing information that I think is critical in order to understand this.
Properties
Properties are simply values that are associated with an object and may be queried in a trivial amount of time without the need (or ability) for parameters like methods have.
Stored Properties
When you create a stored property, whether with let or var, the value assigned at any given point in time will be stored in memory, which is why it is called a stored property.
var name = "Matt"
For variables using var, the value is stored in memory in a way that makes it mutable (editable). You can reassign the value at will and it will replace the previous value stored in memory.
let name = "Matt"
For constants using let, the value is also stored in memory, but in such a way that it may not be changed after the first time assigning to it.
Computed Properties
Computed properties are not stored in memory. As ganzogo says in the comments, computed properties act similarly to methods, but do not take parameters. When deciding when to use a computed property or a function with no parameters, the Swift API Design Guidelines recommend using a computed property when it will simply create or fetch, and then return the value, provided that this takes a trivial amount of time.
var fullName: String {
return firstName + lastName
}
Here, we assume that firstName and lastName are already properties on the object. There is no sense of initialization with this property because it is not stored anywhere. It is fetched on demand every time. That is why there is no sense to doing anything like the following:
var dogName : String {
return "Buster"
}
This has no benefit over a stored property except that no memory will be used in storing the String "Buster".
In fact, this is a simplified version of computed properties. You will notice that the Swift Language Guide describes the use of both get and set in a computed property. set allows you to update the state of other variables when one sets a computed variable. For example:
var stored: Int
var computed: Int {
get {
return stored + 5
}
set {
stored = newValue - 5
}
}
Some useful applications of this were pointed out by Rajan's answer, for example getting and setting volume from width, height, and depth.
A read-only computed var is just a computed var which specifies only a getter, in which case the get keyword and brackets are not required.
Read-Only for Access Control
When developing modules such as frameworks, it is often useful to have a variable only be modifiable from within that object or framework and have it be read-only to the public.
private var modifiableItem: String
public var item: String {
return modifiableItem
}
The idea here is that modifiableItem should only be mutable from within the object that defined it. The private keyword ensures that it is only accessible within the scope of the object that created it and making it a var ensures that it may be modified. The public var item, then, is a computed variable that is exposed to the public that enables anyone to read, but not mutate the variable.
As Hamish notes in the comments, this is more concisely expressible by using private(set):
public private(set) var item: String
This is probably the best way to go about it, but the previous code (using a private stored property and public computed one) demonstrates the effect.
let dogName = "Buster"
means that the dogName variable can't be changed later on once assigned "Buster" and it becomes constant
var dogName : String {
return "Buster"
}
It is a computed read only property where you can have some calculation which can be changed as it is a var but in a way defined below:
The computed property can be changed like
var dogName : String {
return "Stress"+"Buster"
}
Consider this example from Apple Docs
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
It will print
// Prints "the volume of fourByFiveByTwo is 40.0"
Here the volume is calculated when you initialize the object of struct Cuboid and is computed at run time. If it was let, then you have to initialize it before using by some constant.
If you want to read more about it, read the Computed Properties section here
In your example, they are 2 ways of doing the same thing. However, you can do a lot more with a computed property. For example:
var dogName: String {
return firstName + " " + lastName
}
Here, firstName and lastName might not be known at initialization time. This is not possible to do with a simple let property.
It might help you to think of a computed property as a method with no parameters.
A read-only property in a class/struct means that you can't change the value of the property for that instance of the class/struct. It prevents me from doing:
someObject.dogName = "Buddy" // This fails - read-only property
However, I can still do this:
var someVariable = someObject.dogName // someVariable now is "Buster"
someVariable = "Buddy" // This is OK, it's now "Buddy"
A let constant means you won't be changing the value of that specific constant in that block of code.
let someName = "Buster"
someName = "Buddy" // This fails - someName is a constant
There are two different cases:
1) Value type:
struct DogValueType {
var name: String
}
let dog1 = DogValueType(name: "Buster")
var dog2: DogValueType {
return DogValueType(name: "Buster")
}
let dog3: DogValueType = {
return DogValueType(name: "Buster")
}()
dog1 - dog3 can't be changed or mutated
dog1 & dog3 stores value
dog3 computes value each time you accessing it
2) Reference type:
class DogReferenceType {
var name: String
init(name: String) {
self.name = name
}
}
let dog4 = DogReferenceType(name: "Buster")
var dog5: DogReferenceType {
return DogReferenceType(name: "Buster")
}
let dog6: DogReferenceType = {
return DogReferenceType(name: "Buster")
}()
dog4 - dog6 can't be changed, but can be mutated
dog4 & dog6 stores reference to an object.
dog5 creates object each time you accessing it
I have a weird situation in Swift 2 where in a certain situation when I reference a property, the property's set observers are called.
The following code sample illustrates the issue:
var i = 0
protocol PropertyProtocol {
var name: String { get }
}
class PropertyType: PropertyProtocol {
var name = "Bob"
}
class AggregateType {
var prop: PropertyProtocol! {
willSet {
i += 1
print("a set will be done")
}
}
}
let a = AggregateType()
i // i = 0, since prop was not set.
a.prop = PropertyType()
i // i = 1, since prop was just set.
// This is where it gets weird
a.prop.name
i // i = 2
a.prop.name
i // i = 3
This problem doesn't appear prior to Swift 2, as this same code in Xcode 6.4 doesn't reproduce the issue, but keeps i = 1 no matter how many times a.prop.name is called.
A temporary workaround I have found for this issue is transferring the internal property to another temporary variable in the current scope and referencing its internal properties using the temp var.
i // i = 1
let prop = a.prop
prop.name
i // 1 = 1
But this makes my code uglier for no reason other than to compensate for this bug.
Anyone knows of this issue? Is there anyway to solve this more fundamentally?
That's a bug which has been fixed in Xcode 7.2 beta 2. From the
release notes:
In previous releases of Swift, if a type had a mutable property of
protocol type, "chained" accesses to properties of that property were
always treated as mutations of the property, even if the second
property was only read, not written.
...
The workaround was to split the access into separate expressions ...
...
This bug has now been fixed. (22953072)
The workaround suggested here is exactly what you already figured out.
I am trying to write in swift something that should be very basic, but I can't seem to get a handle on it :
First, I create a global variable. For example:
var xx:Int
Then, I want to create a conditional instruction. Something like :
if (xx == 1){
//do something
}
else if (xx == 2) {
//do something else
}
I can do this very easily in Objective-C, but I can't seem to be able to do it in Swift. I have looked everywhere, and don't seem to find the answer.
With the code you provided you're probably getting the error: "Variable xx used before initialized". This is happening because the declaration of the variable is incomplete, you neither gave a value to the variable nor told the compiler it is an optional. You have three options:
Give a initial value to it; var xx: Int = //value here
Declare it as an optional (doing this you say that it may not have a value, if it does the code will be executed, if it doesn't it won't); var xx: Int?
Force unwrap the variable (it still an optional, but if you force-unwrap it you're assuring the compiler that the variable will have a value when needed, otherwise it'll crash); var xx: Int!
Or you can say var xx = Int() that way it's initialized and the default initialization is equal to 0. This is different than the other answers and allows you to have a value from the get go if you're not sure what value might be assigned during runtime.
In addition to the other poster's point that you must assign an initial value before you can use xx, you also need to lose the parentheses around the condition in your if statement:
var xx:Int
xx = 2
if xx == 1
{
//do something
}
else if xx == 2
{
//do something else
}
As Apple Documentation says:
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. This means you can use constants to name a value that you determine once but use in many places.
Let's consider some class:
class A {
var a = [String]()
}
Since array a is mutable, it's defined via var. But what if we consider class B, where instance of A is property?
class B {
let b = A()
}
Even if b is mutable, let keyword will be ok, because reference won't be changed. On the other hand, var will be ok too, because content of b can be changed. What should I pick in this example - let or var?
Use let whenever you can. Use var when you must. Making things immutable makes a lot of bugs impossible, so it should be your default choice. As much as possible, set all your values in init and never change them. Similarly, you should use struct when you can, and class when you must (though in my experience this is harder to achieve than using let).
So in your example, if you cannot set A.a during initialization, then yes, it should be var. But there is no need in your example to use var for B.b. (And there's no reason in either example to use class, at least in the way you've presented the question.)
Let's give these better names to help with our reasoning. Let's say
class Head {
var hairs = [String]()
}
class Person {
let head = Head()
}
In this example, a Person has exactly one head, and for the lifetime of each Person, his/her head will always been that same head. However, that head's hairs can grow in, fall out, or otherwise change. Person's ownership of this head has no bearing on the Head's relationship to its hairs.
As Rob mentioned, you should always use let unless you have a good reason not to. Immutability is your friend when it comes to reasoning about program behavior.
Use let when your object does not change its value after has been set a value.
Use var if your object can change its value more than 1 time.
'let' is for constance. 'var' is for something variable.
However, constant restriction is only applied to the object but not its attributes if the object is an instance of class (value are passed by reference). Depending on type of those attributes (constant or variable), we can change their value after. This is not true for structure.
For example:
class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}
in a function, you declare
let vm = VideoMode()
print("starting framerate is \(vm.frameRate)") // -> print starting framerate is 0.0
vm.frameRate = 20.0
print("framerate now is \(vm.frameRate)") // -> print framerate now is 20.0
//we can change .frameRate later to 10.0, there is no compile error
vm.frameRate = 10.0
print("framerate now is \(vm.frameRate)") // -> print framerate now is 10.0
When you declare a variable with var, it means it can be updated, it is variable, it’s value can be modified.
When you declare a variable with let, it means it cannot be updated, it is non variable, it’s value cannot be modified.
var a = 1
print (a) // output 1
a = 2
print (a) // output 2
let b = 4
print (b) // output 4
b = 5 // error "Cannot assign to value: 'b' is a 'let' constant"
Let us understand above example: We have created a new variable “a” with “var keyword” and assigned the value “1”. When I print “a” I get output as 1. Then I assign 2 to “var a” i.e I’m modifying value of variable “a”. I can do it without getting compiler error because I declared it as var.
In the second scenario I created a new variable “b” with “let keyword” and assigned the value “4”. When I print “b” I got 4 as output. Then I try to assign 5 to “let b” i.e. I’m trying to modify the “let” variable and I get compile time error “Cannot assign to value: ‘b’ is a ‘let’ constant”.
Source: https://thenucleargeeks.com/2019/04/10/swift-let-vs-var/