I am able to write mutating functions in structure but not in class.
struct Stack {
public private(set) var items = [Int]() // Empty items array
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int? {
if !items.isEmpty {
return items.removeLast()
}
return nil
}
}
In swift, classes are reference type whereas structures and enumerations are value types. The properties of value types cannot be modified within its instance methods by default. In order to modify the properties of a value type, you have to use the mutating keyword in the instance method. With this keyword, your method can then have the ability to mutate the values of the properties and write it back to the original structure when the method implementation ends.
If you change the struct to a class, just delete the keyword mutating wherever it appears.
That's because classes are reference types, and structures are value types.
struct TestValue {
var a : Int = 42
mutating func change() { a = 1975 }
}
let val = TestValue()
val.a = 1710 // Forbidden because `val` is a `let` of a value type, so you can't mutate it
val.change() // Also forbidden for the same reason
class TestRef {
var a : Int = 42
func change() { a = 1975 }
}
let ref = TestRef()
ref.a = 1710 // Allowed because `ref` is a reference type, even if it's a `let`
ref.change() // Also allowed for the same reason
So on classes, you don't need to specify if a function is mutating or not, because, even when defined with let variables, you can modify instance...
That's why the mutating key word has no meaning on classes.
Related
I feel like something is broken with the value semantics here. Consider:
struct A {
var b = 0
mutating func changeB() {
b = 6
}
}
struct B {
var arr = [A]()
func changeArr() {
/* as expected this won't compile
unlss changeArr() is mutating:
arr.append(A())
*/
// but this compiles! despite that changeB is mutating!
for var a in arr {
a.changeB()
}
}
}
Why can this example mutate the struct contents without marking the function as mutating? In true value semantics, any time you change any part of the value, the whole value should be considered changed, and this is usually the behavior in Swift, but in this example it is not. Further, adding a didSet observer to var arr reveals that changeArr is not considered mutation of the value.
for var a in arr {
a.changeB()
}
This is copying an element from arr out into a and leaving arr unchanged.
If you directly access the elements inside arr via their indexes, then it will mutate and require the mutating keyword.
The reason changeArr is not mutating is because it isn't really doing anything since it is working on local copies of the A objects. If you really want the method to do something meaningful it needs to be changed to
mutating func changeArrForReal() {
for index in arr.indices {
arr[index].changeB()
}
}
In the following example, you can see that the dictionary in the myStruct instance is not returned by reference in the getDictionary() function. Therefore, any changes made to the returned dictionary is only made to the copy. How can you return the dictionary by reference?
struct myStruct {
func getDictionary() -> [Int:String] {
return dictionary
}
private var dictionary = [1:"one"]
}
let c = myStruct()
var sameDict = c.getDictionary()
sameDict[2] = "two"
print(c.getDictionary(), sameDict)
[1: "one"] [1: "one", 2: "two"]
Dictionary is a value type, it is not your choice to do some type of data structure to be reference or value, it is a Swift's choice. Only closure, class and functions can be used as reference
In Swift, Array, String, and Dictionary
https://developer.apple.com/swift/blog/?id=10
Because the Dictionary is a struct type, the only way to do this is by passing it in a function using inout keyword (indicates that the parameter will be changed) like this:
struct MyStruct {
func getDictionary() -> [Int: String] {
return dictionary
}
mutating func updateDictionary(block: (inout [Int: String]) -> Void) {
block(&dictionary)
}
private var dictionary = [1:"one"]
}
var c = MyStruct()
c.updateDictionary {
$0[2] = "two"
}
print(c.getDictionary())
Update: After modification of the copy inside the function, before the return, the modified copy WILL assign to the global variable. #AlexanderNikolaychuk and #matt pointed out that in the comments. The behavior can be seen if you run the following code in a Playground:
struct MyStruct {
var some = 1
}
var myStruct = MyStruct() {
didSet {
print("didSet")
}
}
func pass(something: inout MyStruct) {
something.some = 2
print("After change")
}
pass(something: &myStruct)
this will print:
After change
didSet
Just saying.
It seems that you did not quite understand the difference between struct and class.
When you initialise the struct and assign it to c you have your first copy of it. Then you initialise a new variable, calling it sameDict and copying the value of the c dictionary to it. Then you modify the copy called sameDict. The dictionary of c is still the same.
Check this doc:
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
Stuct's are passed around by copying them. classes get referenced.
Consider this class in Swift:
class Zombie: Monster {
var walksWithLimp = true
final override func terrorizeTown()
{
town?.changePopulation(-10)
super.terrorizeTown()
}
func changeName(name: String, walksWithLimp: Bool)
{
self.name = name
self.walksWithLimp = walksWithLimp
}
}
Zombie inherits the name field from the Monster class.
var name = "Monster"
Why does
fredTheZombie.changeName("Tom", walksWithLimp: true)
work even if there is no mutating keyword before the function header?
From The Language Guide - Methods:
Modifying Value Types from Within Instance Methods
Structures and enumerations are value types. By default, the
properties of a value type cannot be modified from within its instance
methods.
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behavior for that method. The method can then mutate (that is, change)
its properties from within the method, and any changes that it makes
are written back to the original structure when the method ends. The
method can also assign a completely new instance to its implicit self
property, and this new instance will replace the existing one when the
method ends.
You can opt in to this behavior by placing the mutating keyword before
the func keyword for that method ...
Hence, we need to include the keyword mutating to allow a member (e.g. a function†) of a value type to mutate its members (e.g. the member properties of a struct). Mutating a member of a value type instance means mutating the value type instance itself (self), whereas mutating a member of a reference type instance will not mean the reference of the reference type instance (which is considered self) is mutated.
Hence, since a class is a reference type in Swift, we need not include the mutating keyword in any of the instance methods of your Zombie class, even if they mutate the instance members or the class. If we were to speak of mutating the actual class instance fredTheZombie, we would refer to mutating its actual reference (e.g. to point at another Zombie instance).
[†]: As another example, we may use e.g. mutating getters (get); in which case we need to mark this explicitly as these are nonmutating by default. Setters (set), on the other hand, are mutating by default, and hence need no mutating keyword even if they mutate members of a value type.
mutating is not relevant for classes, it is only for value types, such as struct and enum
Without mutating func
struct Counter {
let count: Int
init(count: Int = 0) {
self.count = count
}
// the functional approach
func counterByIncrementing() -> Counter {
let newCount = count + 1
return Counter(count: newCount)
}
}
var counter = Counter()
counter = counter.counterByIncrementing()
Mutating func
struct Counter {
// this now has to be a var :/
var count: Int
init(count: Int = 0) {
self.count = count
}
// the mutating keyword approach
mutating func increment() {
count += 1
}
}
var counter = Counter()
counter.increment()
In class, all func are mutating. But for struct and enum we need to specify.
Another easy to understand example, verified in Swift 3 & 4
struct City
{
var population : Int
func changePopulation(newpopulation : Int) {
population = newpopulation //error: cannot modify property "population"
}
}
var mycity = City(population : 500)
mycity.changePopulation(newpopulation : 2000) //error: cannot modify property "population"
Solution
mutating func changePopulation(newpopulation : Int)
I have a var
var soketTasksList:Set<SocketTask> {
get { return socketManager.tasksList }
}
I don't need to set, only get,
but I need do something like this
soketTasksList.remove(task)
but compiler says
Cannot use mutating member on immutable value is a get-only property
I tried to add the keyword 'mutating' to the get, but this isn't working. I also
tried to add 'mutating' to the var, but this isn't working either.
UPD
i dont undestand why do I need set?
if i do
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
i can
getSoketTasksList().remove(task)
why not with var?
i don't need to set, only get
Yes, you do need to set.
i need do something like this soketTasksList.remove(task)
That is a mutation. Mutating a value type like Set requires the ability to set. But you have cut off that possibility by making this a read-only computed variable.
UPD i dont undestand why do I need set? if i do
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
i can
getSoketTasksList().remove(task)
No you can't. Try it. Here's a playground test:
class CXSocketTask:NSObject{}
class SocketManager {
var tasksList = Set<CXSocketTask>()
}
let task = CXSocketTask()
let socketManager = SocketManager()
socketManager.tasksList.insert(task)
func getSoketTasksList() -> Set<CXSocketTask> {
return socketManager.tasksList
}
getSoketTasksList().remove(task)
The last line generates an error: "cannot use mutating member on immutable value: 'getSoketTasksList' returns immutable value".
You can use temporary variable for this purpose:
var list = soketTasksList
list.remove(task)
Note that underlying list (socketManager.tasksList in this case) remains untouched.
The only situation in which you can do this is if the actual mutating is done through something which is settable.
For example:
struct Person {
var age: Int = 1
mutating func setAge(a: Int) -> Int {
age = a
return a
}
var computedAge: Int {
mutating get {
setAge(a: 4)
return age
}
}
}
var person = Person()
print(person.computedAge) //Prints 4
This is by design
Is something like
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
Update for Swift 4
Swift 4 now support this feature! read more in here
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray) at the end of your function and it all just works. Lots of stdlib now returns Any erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A concrete, so it's much easier to work with.
If you want to keep the CollectionType, then you need to restrict it at the point that you create a function that needs it. For example:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
This isn't ideal, since it means you can have A with the wrong kind of collection type. They just won't have a sum method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
So you can implement blueprints for your generic collection types in you protocol A, and implement these blueprints in the "interface type" B, which also contain the actual collection as a member property. I have taken the largestValue() method above from here.
Example usage:
/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c