Can't implement this design template in Swift?

I know that this template has a name, I don’t remember what it is. Basically, there is a method that returns a transition / springboard property that manipulates the original through an API. Mediator possible?

I tried to implement this in a simple example in the Swift playground:

 struct Count { var value = 0 func adjuster() -> Adjuster { return Adjuster(target:self) } } struct Adjuster { var target:Count func increment(delta:Int) { self.target.value = self.target.value + delta } } var f = Count() f.adjuster().increment(13) 

The first thing this does is help me say that the increment method should be marked mutating . I don’t understand why. I would understand why if he mutated his own var, but not var of another. Well. Therefore, I allow the insertion of an IDE for me. But then he has problems with the last line of the "test". It causes this error:

 ...: error: cannot use mutating member on immutable value: function call returns immutable value f.adjuster().increment(13) ~~^~~~~~~~~~ 

I do not quite understand what the problem is. And he does not offer a “fix it” for me. So what's going on here? How to implement this template?

+5
source share
2 answers

You must change the struct to class to make it work.

Because struct copied by value, so in this line

 return Adjuster(target:self) 

The adjuster will receive a new copy of the target and save it. In the increment method, you are trying to change self.target.value , which means that you are changing self.target , so you are essentially changing self .

But there are more problems because struct is a value type, therefore

 var count: Count // count.value = 0 var adjuster = count.adjuster() adjuster.increment(1) 

count.value expected to be 1, however this is not the case. count.value will remain 0, and adjuster.target.count will be 1. Now you enter the code now very confusing, and you are wondering what happened.

The real problem is that you are introducing a design pattern from OOP with a primitive for a purely functional template, so they do not work together well.

If you are attached to a best practice guide and prefer a struct over class , you can also use a functional approach. those. no mutation

 struct Count { let value = 0 } func increment(count:Count, delta:Int) -> Count { return Count(value:count.value + delta) } 
+2
source

With struct (as opposed to class ), if your method changes its property (-ies), it should be marked with the mutating .

In your case, it should look like this:

 mutating func increment(delta:Int) { ... } 

From the documentation :

Structures and enumerations are value types. By default, value type properties cannot be changed from its instance methods.

However, if you need to change the properties of your structure or enumeration in a specific method, you can choose the change method for this method. Then this method can mutate (i.e. change) its properties inside the method, and any changes that it makes are written back to the original structure when the method ends.

"I would understand why if he mutated his own var, but not var of another."

The reason she still complains about the "mutation", although this is not her own property, but the property of the other, is that both are values. This means that if you change the Count property inside Adjuster , you will still change Count (this is the type of value, not the object). Consequently, the need is mutating .

I don’t see the implementation of Foo , so I can’t say exactly why the last error message is, but I think it has the same reason, that is, value types are not suitable for hosting the -patterns design. That way, you might be better off with classes, not structures.

+3
source

Source: https://habr.com/ru/post/1237889/


All Articles