I want to use the return value of methods directly.
For example in C++, we can use:
//Some codes
cout << obj1.get_foo() << endl;
int a = obj2->get_value() + 100 + obj2->get_value();
or
//...
obj1->set_color("BLUE");
cout << "Color is:" << obj1->get_color();
printf("Color is: %s", obj1->get_color()); // C Version
When I do this in ABAP like:
OBJ1->SET_COLOR( 'BLUE' ). "That's OK.
WRITE:/ 'Color is:', OBJ1->GET_COLOR( ). "Error!
And I expected this output:
Color is: BLUE
Edit: I used Parameter word in Title not as ABAP Keyword, but as function arguments.
What you can do is.
* before 740
OBJ1->SET_COLOR( 'BLUE' ).
DATA COLOR TYPE NAME.
COLOR = OBJ1->GET_COLOR( ).
WRITE:/ 'Color is:', COLOR.
or
* since 740
OBJ1->SET_COLOR( 'BLUE' ).
DATA(COLOR) = OBJ1->GET_COLOR( ).
WRITE:/ 'Color is:', COLOR.
Best regards,
Tapio
An other solution:
DATA : STRING TYPE STRING.
CONCATENATE 'Color is:' OBJ1->GET_COLOR( ) INTO STRING SEPARATED BY ' '.
WRITE :/ STRING .
if you have a multilingual application, with this method, you can get the right language for 'Color is:' at the same time.
Related
In the following simple for loop we create an array (#a) by incrementing a typeless variable ($n):
my #a = do for 1..3 {
state $n;
$n.^name, $n++;
}
say #a;
The result is "kind of" expected:
[(Any 0) (Int 1) (Int 2)]
And I say "kind of" because I've expected as the first value of $n the "undefined" value (Any).
It is like, after the first value is produced (Any) and as we increment the $n (after the first increment of $n we have a casting to an Int) there is also some time warping event in the assignment and we get also the first value to change. So we end up having the first value as 0 (zero).
Can somebody explain the exact mechanism of this behaviour?
see Any.pm6#L519, the candidate
multi sub postfix:<++>(Mu:U $a is rw) { $a = 1; 0 }
is used.
There are some another candidates for undefined values, you can try
my Bool $x;
dd $x++; #Bool::False
my Num $y;
dd $y++; #0e0
As the title asks. I am interested in knowing if the DM scripting language is capable of handling references and pointers, like you would find in c/c++ as *a and &a. I'm guessing the capability exists at some level, owing to the way inbuilt functions like fitgaussian() work. If this capability is open to the user, it would make it easier to code up some classes and functions I want to create.
Yes, it does and it actually is quite similar to C++.
(But the simplification of the script language obscures it a bit.)
I'm trying to shed some light on it:
All objects in DM (Image, TagGroup, Component, ROI, ImageDisplay, etc. ) are automatically and always passed by reference, not value.
You can see this in the following example code:
void ModifyImage( image imgTemp )
{
imgTemp = irow
}
Image img := RealImage( "Test", 4, 100, 100 )
img = icol
img.ShowImage()
OKDialog("Act!")
ModifyImage( img )
img.ShowImage()
The actual image img of the main script changes. The routine ModifyImage received and used a reference to the image object.
Hint: This is a very typical source for bugs when dealing with TagGroups. When one f.e. gets a tag from an image and then modifies it in a method, it changes the tag of the image!
In order to have methods not modify the provided parameter objects passed in by reference, one has to explicitly create a clone of the object first. For this reason, all the object-types in the scripting languages provide ...clone() commands.
void ModifyImage( image imgTemp )
{
imgTemp = irow
}
Image img := RealImage( "Test", 4, 100, 100 )
img = icol
img.ShowImage()
OKDialog("Act!")
ModifyImage( img.ImageClone() )
Now, the img variable of the main script is not changed. (Because we create a copy in memory, and then pass the reference to the copy.)
However, primitive types (string, number) are by default passed by value, not reference.
Again, this can be seen by a little example.
void ModifyString( string tempStr )
{
tempStr = "Changed"
}
string str = "Original"
Result("\n" + str )
OKDialog("Act!")
ModifyString( str )
Result(" --> " + str )
Here the variable str of the main script is not changed by ModifyString because the values was passed into tempStr, and not a reference. The same is true for number type variables.
If one wants to pass a primitive type by reference, this can be denoted with a & in the methods signature.
The example from above now modified:
void ModifyString( string &tempStr )
{
tempStr = "Changed"
}
string str = "Original"
Result("\n" + str )
OKDialog("Act!")
ModifyString( str )
Result(" --> " + str )
The & can also be used for non-primitive objects in DM, if the passed in pointer is allowed to be changed:
Here is an example for this. The method does not modify the provided image, but instead creates a new one and passes back the reference into the pointer.
void ModifyImage( image &imgTemp )
{
imgTemp := RealImage( "New Test" , 4, 200, 200 )
imgTemp = iradius
}
Image img := RealImage( "Test", 4, 100, 100 )
img = icol
img.ShowImage()
OKDialog("Act!")
ModifyImage( img )
img.ShowImage()
Finally: The * operator to denote pointers is never used in DM-scripting.
So I have the following grammar:
top_cmd :cmds
{
std::cout << $cmds.text << std::endl;
}
;
cmds returns [char* str]
: cmd+
{
str = new char('a');
}
;
I get g++ compile error:
"str" was not declared in this scope
If I remove this line
std::cout << $cmds.text << std::endl;
Then compile is fine.
I googled how "$text" is used, it seems to me it is expected to use $text for the purpose of rewrite rules. In my example, the function "cmds" returns "char*" when I remove the offending line and some complex structure when I keep it.
I can think of the following workaround:
1. do not have lower level rules return anything, but pass variable into lower level rules.
2. use re-write rules
But both are pretty big change(my real project is fairly large) considering how much time budge I have.
So is there a short-cut? Basically I do not want to change the grammar of top_cmd and cmds, but I can get the full text of cmds' matching.
I am using ANTLR3C, but I believe this is independent of target language.
I think you should do something like this:
top_cmd :cmds
{
std::cout << $cmds.text << std::endl;}
;
cmds returns [char* str]
: cmd+
{
$str = new char('a'); //added $
}
;
$cmds.text will return the text matched for the rule cmds. If you want to return the str, you should change it for $cmds.str
$text: The text matched for a rule or the text matched
from the start of the rule up until the point of
the $text expression evaluation. Note that this
includes the text for all tokens including those
on hidden channels, which is what you want
because usually that has all the whitespace and
comments. When referring to the current rule,
this attribute is available in any action including
any exception actions.
from the Definitive Antrl reference
I wrote a program that will determine whether some imaginary school would have a snow day or not. I have the program working correctly I'm just having an issue.
Basically what I want is for the True/False to be Y/N. And later when I print SnowDay --tells whether there's a snow day. Then it will print either "Yes" or "No" instead of "True" or "False"
SofieAssignment : Boolean;
SnowDay : Boolean;
.
.
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
Get(Item => SophieAssignment);
.
.
Put(Item => "Should we have a snow day today? " & Boolean'Image (SnowDay));
Assuming I understand what you're trying to do:
(1) If you want the user to enter Y or N for SophieAssignment, there are a couple possibilities:
You can input a string and analyze the string yourself.
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
declare
Answer : String := Get_Line; -- Get_Line is in Ada.Text_IO
begin
if Answer = "Y" or else Answer = "y" or else Answer = "Yes" or else
Answer = "yes" then
SophieAssignment := True;
elsif Answer = "N" or else Answer = "n" or else Answer = "No" or else
Answer = "no" then
SophieAssignment := False;
else
-- whatever you want to do for an invalid entry
end if;
end;
(This could be improved, but I'm just trying to cover the fundamental approach.) Another possibility is to define your own enumeration that has the values Y and N:
type Yes_No is (N, Y);
package Yes_No_IO is new Enumeration_IO (Yes_No); -- Enumeration_IO is in Ada.Text_IO
Answer : Yes_No;
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
Yes_No_IO.Get(Item => Answer);
SophieAssignment := (Answer = Y);
Get here will set Answer to either Y or N if the user enters the enumeration name (in either case); it will raise Data_Error if something else is entered. I'd prefer the first method if you want better control over how input is handled. For the second, if the user enters "Y Z", Get will return the Y, and the Z is left in the input stream waiting for the next input operation. Also, the first method allows for multiple possible answers better than the second, although you could make it work with an enumeration like
type Yes_No is (N, No, Y, Yes);
(2) To output "Yes" or "No" based on a Boolean, you can use a function as in Keith's answer, or you can set up an array:
type Const_String_Acc is access constant String;
Yes_No_Image : constant array (Boolean) of Const_String_Acc :=
(False => new String' ("No"),
True => new String' ("Yes"));
Put(Item => "Should we have a snow day today? " & Yes_No_Image (SnowDay).all);
To print a Boolean value as "Yes" or "No", just write a function:
function Boolean_Image(B: Boolean) return String is
begin
if B then
return "Yes";
else
return "No";
end if;
end Boolean_Image;
and use it in place of Boolean'Image.
To read a value from the user as Y or y for True, or as N or n for False, just read a Character value and test it to determine which Boolean value to set. Think about how you want to respond if the character the user enters is not any of Y, y, N, or n. You can use Get_Immediate to read a single character without waiting for a newline on input.
type Snow_Day_Type is new Boolean;
function Yes return Snow_Day_Type is (Snow_Day_Type'(True));
function No return Snow_Day_Type is (Snow_Day_Type'(False));
What I am trying to do is fairly elementary however I am having trouble with my project. My project is too large to include everything, so I will just include the two functions that I am writing along with what the txt file looks like. This is in c++.
bookmark.cfg
No Title
0 0 0 0 0 0
No Title
1 1 1 1 1 1
No Title
2 2 2 2 2 2
No Title
3 3 3 3 3 3
No Title
4 4 4 4 4 4
No Title
5 5 5 5 5 5
These are my two functions for writing and reading to the text file and my class's private structure
struct BookMark {
std::string strFilename;
unsigned id;
unsigned bookID;
unsigned chapterNumber;
unsigned pageNumber;
unsigned lineNumber;
unsigned columnNumber;
}; // BookMark
// ----------------------------------------------------------------------------
// readConfigFile()
bool BookManager::readConfigFile() {
using namespace std;
// Just To Be Safe Incase This Function Is Called In Multiple Places
_mBookMarks.clear();
ifstream inFile( _strConfigFilename );
if ( inFile.fail() ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " failed, could not open " ) + _strConfigFilename + std::string( " \nfor reading in book mark information \nInvalid file or file does not exist" ) );
}
// Read In The Book Mark Contents
std::vector<BookMark> vBookMarks;
BookMark bookMark;
string tempString = "";
if ( inFile.is_open() ) {
while ( !inFile.eof() ) {
BookMark bookMark;
getline( inFile, bookMark.strFilename );
inFile >> bookMark.id;
inFile >> bookMark.bookID;
inFile >> bookMark.chapterNumber;
inFile >> bookMark.pageNumber;
inFile >> bookMark.lineNumber;
inFile >> bookMark.columnNumber;
getline( iniFile, tempString );
//_mBookMarks.insert( make_pair( bookMark.id, bookMark ) );
vBookMarks.push_back( bookMark );
}
}
inFile.close();
return true;
} // readConfigFile
// ----------------------------------------------------------------------------
// writeConfigFile()
bool BookManager::writeConfigFile() {
using namespace std;
ofstream outFile;
outFile.open( _strConfigFilename, fstream::out );
if ( outFile.fail() ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " failed, could not open " ) + _strConfigFilename + std::string( " \nfor writing book mark contents to file." ) );
}
// Write Out Book Mark Contents
if ( outFile.is_open() ) {
unsigned i = 0;
for ( i = 0; i < _mBookMarks.size(); i++ ) {
outFile << _mBookMarks.at( i ).strFilename << endl;
outFile << _mBookMarks.at( i ).id << " ";
outFile << _mBookMarks.at( i ).bookID << " ";
outFile << _mBookMarks.at( i ).chapterNumber << " ";
outFile << _mBookMarks.at( i ).pageNumber << " ";
outFile << _mBookMarks.at( i ).lineNumber << " ";
outFile << _mBookMarks.at( i ).columnNumber << endl << endl;
}
}
outFile.close();
return true;
} // writeConfigFile
The problem I am having is, when I call the write function all the text is being displayed properly in my text file. The first line should be a string that contains the book's title or filename. The second line should be all unsigned ints to specify parameters to know the position of the bookmark's location. As of now I just populated my classes structure with arbitrary data using a for loop and incrementing each bookmarks parameters just to test these functions. Somewhere else in my code I call my write method first to create this text file and write the contents. This seems to be working fine. Then I call my read method to read in the file and populate a temporary vector of my structure to see if the contents being read from the file are valid. Once I get this to work properly I'll then just populate my class's member variable structure instead.
Here I am reading in the first line using getline function then I am using the stream operators to get the rest of the contents. While I am debugging my code going through the read method and checking my temp vector the first element has the correct value with No Title and each of the parameters are 0. When I check the next element there is no string in the next BookMark structure object and all values are 0. Also there should only be 5 elements in my temp vector and it should break out of the loop, but it continues and never breaks out of the loop. Why is the code behaving like this? What is it that I am doing wrong? How can I change this to get the behavior I am looking for?
If you need to see this class in full let me know, but I think the rest of the class is not important as to what I am trying to do, only these two functions should be enough to describe my situation. Once I get this to work properly then I'll just change the read and write methods to work in binary as opposed to text.
I believe I have solved my own problem. In my read method, I had to add a second getline( this fileStream, tempString ); And now my code appears to be working properly. My vector has the correct values and it only has 5 elements and now breaks out of the loop.