What is the significance of the CHANGING keyword when a method is called in ABAP? - 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.

Related

Passing an rvalue as a ByRef parameter to VB6?

Background: I've got a set of VB6 DLLs that share a common "interface". Whichever version is installed locally has members of this interface invoked via COM interop (from VB.Net code, which I suspect might matter). I noticed today that one of the invocations passes [what I understand to be] an rvalue (hereinafter "an rvalue") to a VB6 function that does not have that particular parameter defined as ByVal.
Example Code:
VB6:
Public Function VB6Function(input As String) As String
' Do interesting things with input
End Function
VB.Net:
' get an instance of the VB6 class and pass our trimmed localString to it
result = vb6Instance.VB6Function(localString.Trim())
' Do interesting things with localString
I have not yet noticed an instance of the VB6 code changing the value of input, but I also haven't done an exhaustive search of the different DLL implementations (there are several hundred).
What would happen if VB6Function did change the value of input when input is "an rvalue"? For that matter, why doesn't this method invocation simply error out when "an rvalue" is passed?
What would happen if VB6Function did change the value of input when input is "an rvalue"?
Nothing. Or rather, nothing interesting.
When the called function changes the value of its argument, it makes no difference for the insides of that function whether the argument was provided byval or byref. All that matters is that there is a variable of certain type, thus, it can be acted upon.
For that matter, why doesn't this method invocation simply error out when "an rvalue" is passed?
Why would it error out? The passed argument as correct type (string), that is all that matters.
There is no notion of an rvalue in VB.
When you pass what you would call an rvalue to a method accepting something by reference, the compiler automatically passes the reference to a temporary location where the rvalue actually resides. The method gets its value byref, the caller does not care about pointers.
localString.Trim() allocates and returns a string. It has an address and can be passed around. Your code does not explicitly capture that address, but the compiler has no problem passing it to VB6Function byref. If VB6Function changes the value, it changes what that temporary location points to, which has no observable difference because it's going to be destroyed after the call either way.
As for why some people may have preferred receiving strings byref in VBA, it's specifically to avoid copying the entire string each time when calling the function. In VB.NET it's not a problem because strings there are immutable and therefore can be passed byval without copying, but in VBA that is not the case, so a byval string needs to be cloned for the purpose of the call. People avoided that by specifying byref, even though that technically gave them the power to mess with the passed variable.

Moving messages with VBA Outlook

What is the difference between these two lines?
Set MyMsg = MyMsg.Move(MyFolder2)
MyMsg.Move(MyFolder2)
The first one works just fine.
The second one usually gives an "Outlook is not responding" error.
The MailItem.Move method returns the MailItem that has been moved. Usually, properties return values and methods don't return anything. But for several methods, the designers decided it would be handy to have a return value, so they made them return a value (or object).
When you assign a method to a variable, any arguments must be in parentheses or you'll get a syntax error. If you call a method without assigning it to a variable (because you don't care what the method returns or it's one of the methods that doesn't return a value), then the arguments must not be in parentheses (kind of).
Parentheses, when used in places that the compiler does not require them, are the equivalent of saying "evaluate this before doing anything else". It's like how you use parentheses in order of operations so you can say "evaluate this addition operation before you do this multiplication even though that's not the normal order".
The (kind of) remark above is because most of the time when you "incorrectly" put parentheses around something, it doesn't matter.
Application.CreateItem 0
and
Application.CreateItem (0)
are the same. The second one evaluates the argument before it passes it to CreateItem, but evaluating a single integer takes no time and has no ill effects. The parentheses aren't necessary because we're not assigning the results to a variable, but they're not really hurting anything either.
In your second example, you're telling the compiler to evaluate the folder, then send it to the Move method. I don't know what evaluating a folder means, but I gather it's not good. It probably does something like create an array of all the objects in that folder, or something equally intensive. When Outlook is not responding, it means you gave it such a big job that it hasn't checked back in with the operating system in a timely fashion.
So: Use parentheses for arguments when it's on the right side of an equal sign. Don't use them when it's not. There are a few exceptions to that rule, but you may never need to know them.
There is no difference between the two (you just ignore the function result) unless you actually use the MyMsg variable afterwards - after the message is moved, you cannot access it anymore.
Use the first version.

populating 0LOGSYS from transformation rule

I am trying to populate the infoobject 0LOGSYS in a DSO when a load from a datasource occurs. The idea being that you could tell what sourcesystem the data was loaded from that is needed for a certain requirement. As of now I have a routine set up on a transformation rule for 0LOGSYS. No syntax errors, everything runs during the load, but no data is populated. Tried to debug but for some reason my BREAKPOINT is not getting picked up.
Here is the code that I have placed in the routine. Also, I am trying to do this without assigning any source field so maybe that is causing an issue. Not sure though.
TYPE-POOLS: RSSM.
Data: G_S_MINFO TYPE RSSM_S_MINFO.
CALL FUNCTION 'RSDG_ID_GET_FROM_LOGSYS'
EXPORTING
i_source_system = G_S_MINFO-LOGSYS
IMPORTING
e_soursysid = RESULT
EXCEPTIONS
id_not_found = 1.
Solved this a different way. There are runtime attributes that can be pulled from any request via the methods of "if_rsbk_request_admintab_view" which is instanciated automatically at the beginning of each transformation routine. Here is the code that I put in the routine.
*declaring a local variable like the result type LOGSYS
Data: lvSource like RESULT.
*runs a method to get the source system from the runtime attributes of
*the request
*"p_r_request" is an instance of "if_rsbk_request_admintab_view" which
*has many different methods for runtime attributes
lvSource = p_r_request->GET_LOGSYS( ).
RESULT = lvSource.
If this is the complete source code, it's not surprising that nothing is returned. You declare a new structured variable named G_S_MINFO, don't assign any value to it and return its contents. Unless you deleted the steps from your code sample that are supposed to fill the variable with values, it would be a grave bug if anything else than an initial value was returned.
EDIT: Even with the updated code, I still doubt this will work. Now you pass G_S_MINFO-LOGSYS to a function module that supposedly looks up some system ID without initializing it. Garbage in, garbage out. Or in this case, initial value in, initial value out.

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).

How to I pass a checkbox value by reference with 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.