How to I pass a checkbox value by reference with CLI? - c++-cli

I have a GUI app written in C++/CLI which has a load of configurable options. I have some overloaded functions which grab values from my data source and I'd like to connect my options to those values.
So here's a couple of data retrievers:
bool GetConfigSingle(long paramToGet, String^% str, char* debug, long debugLength);
bool GetConfigSingle(long paramToGet, bool^% v_value, char* debug, long debugLength);
I was hoping to pass in the checkbox's Checked getter/setter as follows:
result = m_dataSource->GetConfigSingle(CONFIG_OPTION1, this->myOption->Checked, debug, debugLen);
...but for some reason I get an odd compiler error which suggests the Checked value isn't being passed as I'd expect:
1>.\DataInterface.cpp(825) : error C2664: 'bool DataInterface::GetConfigSingle(long,System::String ^%, char*, long)' : cannot convert parameter 2 from 'bool' to 'System::String ^%'
Previously this code passed the checkbox in and modified the values itself, but I'm keen to break the dependency our data collection currently has on windows forms.
So what am I missing here?
[Edit] I've filled out the function definitions as they originally were to avoid confusion - my attempt to reduce the irrelevent information failed.
I'm fairly certain that the CheckBox getter / setter returns a bool.

Figured I'd clarify my comments from above and make it a "real" answer...
When you call Checked, what you're getting back as a return value is a bool that represents the current state of the CheckBox. It is not, however, a reference to the actual data member that holds the CheckBox's state. In fact, a properly encapsulated class shouldn't give access to it. Furthermore, since Checked returns a bool by value, that bool is a temporary object that doesn't necessarily exist by the time GetCongigSingle is called.
This leaves you with several options. Either pass the bools by value, and later set the CheckBox's state, or pass the CheckBox itself by reference and "check" it wherever you want.

The two overload of the method GetConfigSingleFile that you have mentioned both take two arguments whereas you are passing 4 arguments to the method. Are there any default arguments? If yes, can you please reproduce the original method declarations?
Most probably, the 4 argument overload of this method is expecting a String^% as the 2nd argument. This is what the compiler is suggesting anyway. But if we can have a look at the method declarations that could help diagnosing the problem.

This isn't an answer to my question, but worth being aware of - apparently there's a quirk in passing properties by reference.

Related

How can I invoke a virtual method handle using ByteBuddy's InvokeDynamic class?

I've found the InvokeDynamic class and have made it work with a static method handle acquired via MethodHandles.Lookup.findStatic().
Now I am trying to do the same thing, but with a virtual method handle acquired via MethodHandles.Lookup.findVirtual().
I can cause my bootstrap method to run, and I make sure in my bootstrap method that I'm returning a ConstantCallSite(mh), where mh is the result of calling MethodHandles.Lookup.findVirtual(). (This part all works fine, i.e. I understand how "indy" works.)
However, when I use the resulting Implementation as the argument to an intercept() call, I cannot pass the actual object on which the method represented by the method handle is to be invoked. This is due to the withArgument() method being used for two contradictory purposes.
Here is my recipe:
Implementation impl =
InvokeDynamic.bootstrap(myBootstrapDescription, someOtherConstantArgumentsHere)
.invoke(theMethodName, theMethodReturnType)
// 0 is the object on which I want to invoke my virtual-method-represented-by-a-method-handle;
// 1 is the sole argument that the method actually takes.
.withArgument(0, 1);
There are some problems here.
Specifically, it seems that withArgument() is used by ByteBuddy for two things, not just one:
Specifying the parameter types that will be used to build a MethodType that will be supplied to the bootstrap method. Let's say my virtual method takes one argument.
Specifying how the instrumented method's arguments are passed to the actual method handle execution.
If I have supplied only one argument, the receiver type is left unbound and execution of the resulting MethodHandle cannot happen, because I haven't passed an argument that will be used for the receiver type "slot". If I accordingly supply two arguments to (1) above (as I do in my recipe), then the method handle is not found by my bootstrap method, because the supplied MethodType indicates that the method I am searching for requires two arguments, and my actual method that I'm finding only takes one.
Finally, I can work around this (and validate my hypothesis) by doing some fairly ugly stuff in my bootstrap method:
First, I deliberately continue to pass two arguments, not one, even though my method only takes two arguments: withArgument(0, 1)
In my bootstrap method, I now know that the MethodType it will receive will be "incorrect" (it will have two parameter types, not one, where the first parameter type will represent the receiver type). I drop the first parameter using MethodType#dropParameterTypes(int, int).
I call findVirtual() with the new MethodType. It returns a MethodType with two parameter types: the receiver type that it adds automatically, and the existing non-dropped parameter type.
(More simply I can just pass a MethodType as a constant to my bootstrap method via, for example, JavaConstant.MethodType.of(myMethodDescription) or built however I like, and ignore the one that ByteBuddy synthesizes. It would still be nice if there were instead a way to control the MethodType that ByteBuddy supplies (is obligated to supply) to the bootstrap method.)
When I do things like this in my bootstrap method, my recipe works. I'd prefer not to tailor my bootstrap method to ByteBudddy, but will here if I have to.
Is it a bug that ByteBuddy does not seem to allow InvokeDynamic to specify the ingredients for a MethodType directly, without also specifying the receiver?
What you described, is entirely independent of Byte-Buddy. It’s just the way how invokedynamic works.
JVMS, §5.4.3.6
5.4.3.6. Dynamically-Computed Constant and Call Site Resolution
To resolve an unresolved symbolic reference R to a dynamically-computed constant or call site, there are three tasks. First, R is examined to determine which code will serve as its bootstrap method, and which arguments will be passed to that code. Second, the arguments are packaged into an array and the bootstrap method is invoked. Third, the result of the bootstrap method is validated, and used as the result of resolution.
…
The second task, to invoke the bootstrap method handle, involves the following steps:
An array is allocated with component type Object and length n+3, where n is the number of static arguments given by R (n ≥ 0).
The zeroth component of the array is set to a reference to an instance of java.lang.invoke.MethodHandles.Lookup for the class in which R occurs, produced as if by invocation of the lookup method of java.lang.invoke.MethodHandles.
The first component of the array is set to a reference to an instance of String that denotes N, the unqualified name given by R.
The second component of the array is set to the reference to an instance of Class or java.lang.invoke.MethodType that was obtained earlier for the field descriptor or method descriptor given by R.
Subsequent components of the array are set to the references that were obtained earlier from resolving R's static arguments, if any. The references appear in the array in the same order as the corresponding static arguments are given by R.
A Java Virtual Machine implementation may be able to skip allocation of the array and, without any change in observable behavior, pass the arguments directly to the bootstrap method.
So the first three arguments to the bootstrap method are provided by the JVM according to the rules cited above. Only the other arguments are under the full control of the programmer.
The method type provided as 3rd argument always matches the type of the invokedynamic instruction describing the element types to pop from the stack and the type to push afterwards, if not void. Since this happens automatically, there’s not even a possibility to create contradicting, invalid bytecode in that regard; there is just a single method type stored in the class file.
If you want to bind the invokedynamic instruction to an invokevirtual operation using a receiver from the operand stack, you have exactly the choices already mentioned in your question. You may derive the method from other bootstrap arguments or drop the first parameter type of the instruction’s type. You can also use that first parameter type to determine the target of the method lookup. There’s nothing ugly in this approach; it’s the purpose of bootstrap methods to perform adaptations.

How serious is BC42020 in an upgraded VB .Net project?

Consider the following line of code which used to compile without warnings.
Public SetUpDone = False
After upgrading a project to Visual Studio 2017 from Visual Studio 2005 over a hundred of these BC42020 warnings exist. The MSDN description of the warning simply states that the variable defaults to type object. I don't have a good idea of the seriousness of this type of warning. The debugger indicates that the code executes as I expect. Is it merely a performance type of issue?
Secondly, I thought that Visual Basic supported some form of Type Inference so I'm not clear about why it wouldn't be able to deduce that the type should be Bool.
Another example is the following where the function returns a String
Dim dayTxt = " " & GetTextFromIni("General", "Var50")
I would have thought that type inference would work here and deduce that dayTxt is a String.
This:
Public SetUpDone = False
Is equivalent to this:
Public SetUpDone As Object = False
As suggested, type inference is only for local variables, not fields. With Option Infer On, this inside a method:
Dim SetUpDone = False
would indeed be equivalent to this:
Dim SetUpDone As Boolean = False
There are a couple of issues with the code as you have it. Firstly, it means that every use of that False value requires unboxing which makes your code slower. That's the case for any value types, i.e. structures. Value types are normally stored on the stack but, when boxed, are stored on the heap.
Secondly, it means that any member access will require late binding. That's not an issue for Boolean values because they have no members of interest anyway but if it was, say, a DateTime then the IDE would never provide Intellisense for that type because al it would see would be type Object and the existence of the specified member would have to be confirmed at run time, making the code less efficient again.
Thirdly, it means that the compiler can never confirm that you're passing the correct type as a method argument. For instance, if you have a method with a Boolean parameter, the compiler won't know that you're passing a Boolean if you pass that field because it's type Object. That also means that if you pass some other Object variable that doesn't contain a Boolean, the compiler can't warn you.
As suggested, you should turn Option Strict On in the project properties. That will flag every instance of you're not specifying the appropriate type for something. Fixing those errors will, at the very least, make your code a bit more efficient. It may even draw your attention to situations where exceptions will or could be thrown at run time. Having Option Strict On enforces strict typing so it makes you think more about the types you're using. Even if you're conscientious about that with Option Strict Off, you can still make mistakes that Option Strict On will prevent.

What is the significance of the CHANGING keyword when a method is called in ABAP?

I understand what IMPORTING and EXPORTING keywords do, but what is the significance of the CHANGING keyword?
IMPORTING passes an actual parameter as a formal parameter, thus transferring a value from the caller to the method. EXPORTING does the exact opposite, taking a value from the method and transferring it back to the caller. CHANGING combines these, transferring the value both from the caller to the method an back again, with any changes that happened in between.
Note that while IMPORTING and EXPORTING are reversed between declaration and call, CHANGING is not.
Also, when declaring Subroutines with FORM and ENDFORM, the CHANGING keyword can be used either like CHANGING myvar or CHANGING VALUE(myvar).
CHANGING myvar makes it so that the value of myvar is changed as soon as it is changed in the subroutine.
In contrast, if CHANGING VALUE(myvar) is used, if the form does not return properly (if it throws an exception by example), the value of myvar will remain unchanged, in the calling code, even if it was changed in the subroutine that crashed.

VBA: how to test for object equality (whether two variables reference the same object)

What is the operator or function to test whether two variables of the same custom object type refer to the same object? I've tried
If myObject = yourObject Then
But get a runtime error 438 object doesn't support this property or method. I'm guessing that's telling me to override the '=' operator to test if all the fields of the two objects have the same value. But what I want is to test whether they are the same object.
I'm guessing that's telling me to override the '=' operator to test if all the fields of the two objects have the same value.
No, it tells you the objects don't have a default property which would have been called otherwise, and the returned results compared.
You test reference equality with Is
If myObject Is yourObject Then
You need to serialize the objects somehow and then compare attribute by attribute values. The "is" operator is as dumb as it gets, it only matches if another object is the same instance assigned to the compared variable.
I suggest using a jsonStringify library. I adapted one for my DexTools.xlam open source project https://github.com/dexterial/Dextools/tree/master/Main starting from the Parsing JSON in Excel VBA post. It has much more added features since I added quite a few other excel objects serialization/hashing options and it is made using the vba test driven development that DexTools incorporates. It is still work in progress so dont expect miracles

Handle declarations

Can anyone tell me what the difference is between these 2 lines of code, which one is better to use?
System::String ^MyStr = gcnew System::String(MyStr);
System::String ^MyStr;
Those lines are not equivalent. In the first one, you will get an exception beacuse you're trying to create a String from an uninitialized tracking handle (MyStr). In the second one, MyStr is declared, not defined, it points to garbage and will throw an exception if you attempt to use it. Which one you should use depends on the rest of the code
The second one creates a new handle variable. If it's a local variable, then as #dario_ramos says, it's uninitialized, and your program will likely crash if you try to use the handle before assigning it. If it's a member variable or global, then it will be nullptr.
The first one is similar, although it can only be used for locals or globals (member variables use the ctor-initializer syntax in C++/CLI just like plain C++), and does exactly what you're not permitted to do. It reads the brand new uninitialized handle and passes it to the System::String constructor. If by chance the constructor finishes, a handle to the newly constructed String will be placed into the variable as part of initialization. But because the constructor is trying to make a copy of random garbage (if it's a local) or nullptr (if a global), most likely it will simply crash.
It's a bad idea to use the value of any variable in its own initializer (sometimes you need to use the address, never the value).