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.
Related
I've noticed some interesting behavior in an LWC that I am building and haven't been able to find much info on the cause. Basically I have an Apex method declared with multiple signatures:
// myMethod with 2 param signature
#AuraEnabled
public static void myMethod(String param1, String param2) {
// I expect this method to be invoked when called from the LWC code shown below
....
}
// myMethod with 3 param signature
#AuraEnabled
public static void myMethod(String param1, String param2, Boolean param3) {
// However this method gets invoked instead
....
}
When I attempt to call myMethod from an LWC, and only pass two parameters into the method, I would expect that the 2 param signature method would be invoked, however what happens is that the 3 param signature method is invoked, and the value of null is passed as the third params value.
runJob({param1, param2}).then(value => ... )
Is this expected behavior? When I call the methods through apex, the correct method is invoked by its signature, however this doesn't seem to be the case when calling the method from an LWC.
Is there a way for me to invoke the myMethod Apex method of the correct signature from an LWC?
Edit:
it will be banned at compile time in Summer'22 release. https://help.salesforce.com/s/articleView?id=release-notes.rn_apex_ValidationForAuraEnabledAnnotation.htm&type=5&release=238
Original:
It's worse than you think. runJob({param2, param1}) will work correctly too. "Correctly" meaning their names matter, not the position!
Your stuff is always passed as an object, not a list of parameters. You could have a helper Apex wrapper class and (assuming all fields are #AuraEnabled) it'll map them correctly. If you have list of parameters - well, a kind of unboxing and type matching happens even before your code is called. If you passed "abc" to a Date variable - a JSON deserialization error is thrown even before your code runs, you have no means to catch it.
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.apex_wire_method
If the Apex method is overloaded, the choice of what method to call is
non-deterministic (effectively random), and the parameters passed may
cause errors now or in the future. Don't overload #AuraEnabled Apex
methods.
So... pick different names? Or funnel them so the 3-param version looks at the last param and calls 2-param one if needed and the business logic allows it. Generally - keep it simple, leave some comments and good unit tests or 2 months from now poor maintenance guy will struggle.
And (if you use the Apex PMD plugin and/or sfdx scanner) functions with long parameter lists are frowned upon anyway: https://pmd.github.io/latest/pmd_rules_apex_design.html#excessiveparameterlist
See also
https://github.com/trailheadapps/lwc-recipes/issues/196
https://salesforce.stackexchange.com/questions/359728/apex-method-overloading-is-not-working-when-called-from-lwc-javascript-controlle
I think inout makes you passes in a reference (is that accurate?), then if the reference gets changed many times, as you might do with an array, the array then does not have to copied many times because its now a reference type?
The semantics for in-out parameters in swift is different from passing value by reference. Here's exactly what happens when you're passing an in-out parameter:
In-out parameters are passed as follows:
When the function is called, the value of the argument is copied.
In the body of the function, the copy is modified.
When the function returns, the copy’s value is assigned to the original argument.
This behavior is known as copy-in copy-out or call by value result. For example, when a computed property or a property with observers is passed as an in-out parameter, its getter is called as part of the function call and its setter is called as part of the function return.
See https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545
Array is value type in swift so it's fully copied in this scenario. Of course the swift compiler may optimize that but anyway you're guaranteed to see exact same behavior as it'd be with full copies performed.
If you want to pass an array by reference and allow the called function to modify elements quickly, you have the choice of either explictly creating an NSMutableArray, or creating a class where instances have an array as their single member.
I have a UserForm with a ListBox for the user to select values. Those values are populated in UserForm_Initialize() via a function call to the base module, which returns an array as variant. This works without problems.
If the user selects some values and presses a button, the buttons Click event calls another function in the base module to pass on the user-entered array and compute things. This does not work at all. The value received in the base module is always nonexistent (not even null, but I don't know the correct VBA term, nothing is there at all).
Things I have tried so far:
Passing all arguments ByVal: Did not make a difference
Using global shared variables: This did work, but I don't want to rely on them if all I do is pass a single array to a single function. This also introduces state into the code which has to be managed, especially when reusing the function
Accessing the functions by full qualifiers: Did not make a difference. The functions are found and executed correctly, but the argument variables are empty, therefore the functions fail later on when doing the calculations.
My question is: How can I pass arrays from UserForms to Modules (not vice versa) without relying on global variables and without losing the array content?
This question may be related to this question about passing a String from Form to Module, but the accepted answer does not help in my case (using global variables).
When adding the code as requested in the comments, I stumbled upon that fact that I could print the content of the array, but it would not show anything in the debugger and the size would be 0.
The size issue was because I used Len(array) instead of Application.CountA(array) and I had a leftover On error resume next from earlier still in the code, which meant that no error was raised and size was always set to zero... This was the reason for the strange behaviour.
So I am doing a simple personal project in winforms with F#. My code used to work, but now throws this exception for seemingly no reason.
An unhandled exception of type 'System.InvalidOperationException' occurred in FSharp.Core.dll
Additional information: The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized.
The code is a member method that is being invoked from the constructor of the form itself
do
//lots of other constructor code before this point
// render the form
form.ResumeLayout(false)
form.PerformLayout()
form.ReloadGoals
//several other members before here
member form.ReloadGoals =
let x = 10 //crashes on this line
The website where I grabbed the template for the project I am using is this one.
Unfortunately I have made some substantial additions to this.
I would be glad to post more code, but I need to know what code would be relevant exactly, as I am not exactly sure and don't want to bog down the post in extraneous code.
Also I can't really find a lot of documentation on System.InvalidOperationException.
Every time I find it, it is being used as an example of an exception you can throw on your own, not what causes it.
See The F# 3.0 Language Specification (final version, PDF), §8.6.1 Primary Constructors in Classes:
During construction, no member on the type may be called before the last value or function definition in the type
has completed; such a call results in an InvalidOperationException.
Almost certainly, your code in the question doesn't tell the full story. If you hit the above
mentioned restriction, then there's somewhere an attempt to access a field or member not fully initialized.
Some example:
type X() as this =
let x = this.X
member __.X = 42
X()
One workaround might be to encapsulate the offending code in a member of its own and call that in the constructor instead. Another would be the wrapping in a function definition.
This will be an incomplete answer, since I cannot reproduce the problem (using F# interactive, the given example, the ReloadGoals modification, and Form.Show, the code runs fine). However, there are strange things happening:
Taken from the template, there should be a handler method for the Form.Load event, which fires when the type is fully constructed. Why is additional loading code in the constructor instead of this event handler? Load exists precisely to counter this kind of problem with unorderly initialization.
The template you are using isn't exactly sane F#. For example, initControls is a value of type unit that is evaluated where it is defined; its binding to a name is absolutely useless and should be replaced with a simple do. Writing initControls in the do block later has no effect at all. form.ResumeLayout(false); form.PerformLayout() should be equivalent to form.ResumeLayout(true), but I don't understand what these are doing in the constructor in the first place. The event handlers have two possibly unnecessary indirections: one to a delegate constructor, another to a method that has no real reason to exist -- the handlers should be lambdas or simple, private functions. Why are they public members?!
The error appearing in the question is probably caused by the usage of form in its own constructor. Move your new usage to the Load event handler, and it should work.
Personally, I would go further and ditch implementation inheritance by instantiating a plain Form and subscribing to its events. For example, in FSI, something similar to the template could be done like this:
open System.Drawing
open System.Windows.Forms
let form = new Form()
form.ClientSize <- new Size(600, 600)
form.Text <- "F# Form"
let formLabel = new Label()
formLabel.Text <- "Doubleclick test!"
formLabel.DoubleClick.Add <| fun _ -> form.Close()
form.Controls.Add(formLabel)
form.Show()
which uses no inheritance at all. (In an application, you'd use Application.Run etc instead of form.Show().) This does not run into initialization problems as easily and, additionally, is very useful if you want to encapsulate the form inside a simpler type or even just a function.
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.