Why can't I remove elements from an Array in its willSet event? - arrays

The logic is to clear an Array when it has a specified amount of elements. I could put the check outside of the Array but I was trying to see what if do it in Array's willSet event. The result is elements in Array stay still.
Here is the code
var MyArr=[String]() {
willSet{
print("now count is:\(MyArr.count)")
if MyArr.count>2 {
print("now remove all!")
MyArr.removeAll()
}
}
}
MyArr.append("hello")
MyArr.append(",world")
MyArr.append("!")
MyArr.append("too much.")
print("The conent is \(MyArr)")
MyArr was expected to have only one elements while actual result was four.

The behavior has nothing to do with value type / reference type
Please note the warning
Attempting to store to property 'MyArr' within its own willSet, which is about to be overwritten by the new value
which means that modifying the object in willSet has no effect.

Citing the Language Guide - Properties - Property Observers [emphasis mine]:
Property Observers
Property observers observe and respond to changes in a property’s
value.
...
You have the option to define either or both of these observers on a
property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.
As you are experimenting with the willSet property observer, any mutation of the property you are observing within the willSet block precedes the actual storing of the newValue which follows immediately after the willSet block. This means you are essentially attempting to mutate "the old copy" of myArr prior to it being replaced with its new value.
Arguably this could be discussed as something illegal, as any mutation of myArr should lead to the invocation of any property observers, thus mutation of a property within a property observer (mutation of the reference for reference types or the value for value types) could arguably lead to recursive calls to the property observer. This is not the case, however, and for the willSet case, specifically, instead a warning is emitted, as pointed out in #vadian's answer. The fact that mutation of the property itself within a property observer will not trigger property observers is not really well-documented, but an example in the Language Guide - Properties - Type Properties points it out [emphasis mine]:
Querying and Setting Type Properties
...
The currentLevel property has a didSet property observer to check
the value of currentLevel whenever it is set. ...
NOTE
In the first of these two checks, the didSet observer sets
currentLevel to a different value. This does not, however, cause
the observer to be called again.
This is also a special case we can somewhat expect, as e.g. didSet is an excellent place to incorporate e.g. bounds checks that clamps a given property value to some bounds; i.e., over-writing the new value by a bounded one in case the former is out of bounds.
Now, if you change to mutate the property to after the new value has been stored, the mutation will take affect and, as covered above, not trigger any additional calls to the property observers. Applied to your example:
var myArr = [String]() {
didSet {
print("now count is: \(myArr.count)")
if myArr.count > 2 {
print("now remove all!")
myArr.removeAll()
}
}
}
myArr.append("hello")
myArr.append(",world")
myArr.append("!")
myArr.append("too much.")
print("The content is \(myArr)") // The content is ["too much."]

aAlan's comment on didSet vs willSet is interesting. I tried the same code but with didSet and it did remove the elements from the array which seemed odd initially. I think it's by design. My reasoning is:
if you actually did get a reference to the actual item itself inside willSet and made changes then everything would get overwritten. It makes all your changes nullified. Because you're doing this before you even read what's about to happen. Also (repeating what dfri has said) if you set it again inside willSet well then you're going to trigger the property observer again and again and will create a feedback loop which will crash the compiler, hence the compiler behind the scene creates a copy avoiding all this... will just suppress this mutation ie it won't allow it. It won't create a copy...simply put it would just ignore it. It does that by throwing a vague (because it doesn't really tell you that it will ignore the changes) warning:
same is not true with didSet. You wait...read the value and then make your decision. The value of the property is known to you.

Related

Can React.useMemo second argument array contains an object?

Can React.useMemo second argument array contains an object?
I ask this question because I have an expensive computation based on an object's value.
I don't know should I expand the object, or just simply pass the object into that array.
It is possible to use an object as 2nd argument. But it depends on how the object behaves. If there will be always a new instance of this object each time the affected value(s) has changed, React.useMemo will be able to detect the change. Since React.useMemo will only do an instance compare in case of an object, it will not detect changes within that object if the instance remain the same. If the instance changes more often then the affected properties, it would be better to extract only the required properties and hand them over individually. This will ensure the calculition will only be done if need.

OmitAutoProperties affects non auto property

I have a class that has property like this
public string Foo
{
get { return _foo; }
set
{
if (!string.Equals(_foo, value))
{
_foo= value;
OnPropertyChanged();
}
}
}
When I create object with _fixture = new Fixture {OmitAutoProperties = true};, I expect it has value but it's null and setter never hit. Do I miss something?
This is by design. As the documentation states:
Gets or sets if writable properties should generally be assigned a value when generating an anonymous object.
In other words, in AutoFixture, the term auto-property refers the the feature of AutoFixture that automatically populates writable properties. Perhaps a better word would have been DoNotAutomaticallyPopulateProperties.
I can understand the confusion, as in C#, auto-property can also be interpreted as meaning Auto-Implemented Properties.
Frankly, AutoFixture's terminology should, perhaps, have been chosen with greater care, but in all these years, I don't think this has ever been brought to my attention before.
Specifically in the OP Foo is a writable property, and when you disable auto-properties, the setter is never invoked.
The OmitAutoProperties setting determines if a writable property should be set or not:
Gets or sets if writable properties should generally be assigned a value when generating an anonymous object.
So, if it's true, AutoFixture does not try to set any property values and that is by design.

What does this error actually mean?

So I have seen this error show up, just sometimes, but it is not helpful in describing the actual error which has occured. Nor does it give any clues as to what might cause it to display.
Cannot use modParams with indexes that do not exist.
Can anyone explain more verbosly what this error means, what it relates to (such as a behaviour, component, controller, etc), the most common causes and how to fix it?
To kickstart the investigation, you can find the error here.
https://github.com/cakephp/cakephp/blob/master/lib/Cake/Utility/ObjectCollection.php#L128
Layman's Terms
CakePHP is being told to apply an array of parameters to a collection of objects, such that each particular object can modify the parameters sent on to the next object. There is an error in how CakePHP is being told to do this.
In Depth
Generically, this rises from the CakePHP event publication mechanism. Somewhere in your code is an instance of ObjectCollection, which is being triggered with certain parameters. That is, a method is being called on every object in that collection.
Each callback method is given parameters. Originally the parameters are passed into trigger(). In normal cases (where modParams is false), every callback gets the same parameters. But when modParams is not strictly false, the result of each callback overwrites the parameter indicated by modParams.
So if there are two objects in the collection, modParams is 1, and the params[1] is 'a' initially, then the callback is given the first object with params[1] == a. That callback returns 'b', so when the next callback is called, the second object gets params[1] == b.
The exception raises when the modParams value given does not exist in the originally given params. Eg, if modParams is 2 and params is array (0 => 'a', 1 => 'b'), you'll get this exception.
In your case
Specifically, debugging this has to be done at a low-level because it's a method on a generic class. The backtrace from the Exception should get you bubbled up to a trigger() call on a particular concrete class. That call is being given non-false modParams and a params that doesn't have the given modParams. It could be a code bug in a concrete class extending ObjectCollection, or it could simply be a generic message arising from a method not being given expected arguments.
Have you tried reading the documentation?
/*
* - `modParams` Allows each object the callback gets called on to modify the parameters to the next object.
* Setting modParams to an integer value will allow you to modify the parameter with that index.
* Any non-null value will modify the parameter index indicated.
* Defaults to false.
*/
You did not paste any code, so I guess your 3rd arg of the method contains something wrong.

Difference between CoreceValueCallback and ValidateValueCallback?

I know that CoerceValueCallback is used to correct a value and that ValidateValueCallback will return true or false. But my question is why we need ValidatevalueCallback? We can simply use CoerceValueCallback to validate (using if condition) and correct the value. Can you give some practical example of when to use coercion vs. validation?
Here are the rules I follow for when to use coercion vs. validation.
Use CoerceValueCallback If...
You can safely correct a value to be valid without needing to throw an error.
Your property depends on one or more other dependency properties.
You need to provide instance-level validation as opposed to class-level validation.
You allow others to override your validation logic.
Use ValidateValueCallback If...
You cannot correct a value to be valid.
You must throw an error if an invalid value is provided.
You do not want others to override your validation logic.
So, it primarily depends on whether or not your property depends on other dependency properties or if you want others to be able to override your validation logic.
Since the ValidateValueCallback is not part of the PropertyMetadata, inheritors cannot modify the callback through the DependencyProperty.OverrideMetadata function.
Also, since the ValidateValueCallback does not provide your DependencyObject as a parameter, you cannot perform advanced validation that depends on other dependency properties.
Example 1
Suppose you have Minimum, Maximum, & Value properties. When any of these change, a CoerceValueCallback shoud be used to ensure the other properties are consistent.That is, Minmum <= Value <= Maximum.
However, assuming these values are doubles, then there are some values that would never make sense, namely Double.NaN, Double.PositiveInfinity, and Double.NegativeInfinity. Therefore, a ValidateValueCallback should be used to verify that the double values are normal, numeric values.
In fact, this is exactly how RangeBase works!
Example 2
Suppose you have a RegexTextBox control which takes a string containing a regular expression (call it RegexString). If a bad regular expression is provided, then what should be used instead? It might make sense to coerce it to be a null/empty value, rendering it useless; however, I suggest that this property be validated with a ValidateValueCallback. This is because any error is now thrown at compile-time when designing via the WPF designer.
For this property, there shouldn't be a CoerceValueCallback at all.
There is a whole lot of information describing how to use these callbacks.
I'd suggest taking a look at the MSDN article, Dependency Property Callbacks and Validation, for more in-depth knowledge.
Value coercion is basically to change the value, if the the new value is not as system expected. A best example is Slider control. A Slider has both Minimum and Maximum properties. Clearly, it would be a problem if the Maximum value were allowed to fall below the Minimum value. Value coercion is used to prevent this invalid state from occuring.
Validate value, is something that system will only check whether the given input is valid or not. It will throw Argument Exception if value is invalid (if we returned false for such value). For example, we have Age property, and it should be in range of 0 to 120. In case the new value is 500, the system may warn the user instead coercing it to some hardcoded value.
Any way both callbacks are optional and can be used based on the requirement.

What is the difference between Freezable.Clone() & Freezable.CloneCurrentValue() methods

The documentation says
Clone-
"Creates a modifiable clone of the System.Windows.Freezable, making deep copies
of the object's values. When copying the object's dependency properties,
this method copies expressions (which might no longer resolve) but not animations
or their current values."
CloneCurrentValue-
"Creates a modifiable clone (deep copy) of the System.Windows.Freezable using
its current values."
It means both do deep copy. Then what is the difference?
If I understand the documentation correctly, Clone also copies the binding expressions. So if a property of the object is bound, it remains bound in the copy.
CloneCurrentValues, on the other hand, only copies the current values, as the name implies. Bindings are not kept, so the values in the copy won't be updated if the source of the binding is modified.

Resources