Constructor that takes a static temp table as input (Progress ABL) - progress-4gl

I have a class who's main purpose revolves around a temp table. I want to make a constructor that takes an identical temp table as input.
So far the compiler chokes on any attempt to pass a temp table as a input parameter. If I use a table handle instead, it works. But I'd rather not copy from a dynamic table to a static one.
Progress wants the tables to match up at compile time, but I know they'll be the same - the're defined in a .i file.
Is there an easy way to line up the tables, or am I stuck parsing it out one field at a time?

Works like a charm to me.
CLASS Test.TTOO.TempTableWrapper:
{Test/TTOO/ttCustomer.i}
CONSTRUCTOR PUBLIC TempTableWrapper (TABLE ttCustomer):
FOR EACH ttCustomer:
DISPLAY ttCustomer.CustNum ttCustomer.Name .
END.
END CONSTRUCTOR.
END CLASS.
and the caller:
ROUTINE-LEVEL ON ERROR UNDO, THROW.
USING Test.TTOO.* FROM PROPATH.
DEFINE VARIABLE oWrapper AS TempTableWrapper NO-UNDO .
{Test/TTOO/ttCustomer.i}
/* *************************** Main Block *************************** */
CREATE ttCustomer.
ASSIGN ttCustomer.CustNum = 42
ttCustomer.Name = "It works" .
oWrapper = NEW TempTableWrapper(TABLE ttCustomer ) .
You can also pass the temp-table by-ref:
oWrapper = NEW TempTableWrapper(TABLE ttCustomer BY-REFERENCE) .
However, then the temp-table data is only availalbe during the constructor as BY-REFERENCE calls "overlap" the temp-table within the callee only for the duration of that call.
For permanent "BY-REFERENCE", use the BIND keyword on the call and the paramter - in which case the callee must define the temp-table as REFERENCE-ONLY.
Note, it's not required (although recommended at least by me) to define the temp-tables in include files. At runtime and compile time, the schemas just need to match.
When the compiler does not like your call, delete the classes r-code and recompile.

Related

Lua override class function in included file

I'm sorry I'm new to LUA scripts and I have to work on code written by others.
Please don't focus on code, my problem is only about included files and priority evaluating which function has to be called, in case of overriding.
Let's say I have a file Terrain.lua containing a class Terrain, which has a function Terrain:generate() and Terrain:generate() calls Terrain:getLatitude().
Terrain was included in a script MyScript.lua, which overrided Terrain:getLatitude() as follows:
include("Terrain");
function Terrain:getLatitude()
new code;
end
function myFunction()
local myTerrain = Terrain.create();
myTerrain.generate();
end
This has the effect of overriding getLatitude(): when myTerrain.generate() is called, generate() is the code from the included "Terrain", but getLatitude() is the local function with the new code, even if called by a function from the included class.
Now let's say I want to put some of the code in an external file Custom.lua. Custom (and not MyScript) has to override getLatitude().
This is the situation:
Terrain.lua contains Terrain class and these functions
Terrain.create()
Terrain.generate()
Terrain.getLatitude()
MyScript.lua is the script being executed, and include Custom:
include("Custom");
function myFunction()
return customFunction()
end
Custom.lua contains:
include("Terrain");
function Terrain:getLatitude()
new code;
end
function customFunction()
local myTerrain = Terrain.create();
myTerrain.generate();
end
Now, if I call customFunction() from MyScript, getLatitude() from Terrain is used, instead of getLatitude() from Custom. I assume ovveride is possible only inside the currenti file being executed? How can I achieve overriding in an included file?
I hope this example is enough to understand my problem, without posting a lot of code. Thank you.
Firstly, some corrections: there is no local function's in your question; include is not part of any lua standard, what that function actually does may be quite important.
Finally, Lua does not have actual class system, what you use in the question is merely a syntactic sugar (misleading and confusing as I find it) over table assignments. Lua is an interpreted language, so what may seem to you as a class definition is not a static structure known from the very beginning of the program execution but a code that gets executed from the top of the file to the bottom.
Thus, if we assume that include is similar to the require, then the your question code will be equivalent to the following:
do--terrain.lua
Terrain = {
create=function()
local created_object
--some code to assign value to created_object
return created_object
end
}
Terrain.generate = function(self) end
Terrain.getLatitude = function(this_is_a_self_too)
--some code that uses `also_self` as a reference to the object when called as object:generate()
end
--do end block is essentially an equivalent of file, its local variables are not seen outside
--global variables it has assigned (like `terrain`) will stay accessible AFTER its end
--changes it done to global variables will also remain
end
do--Custom.lua
Terrain.getLatitude = function(this)--this is the assignment to a field in a table stored in the global variable Terrain
--this function will replace the one assigned to the `getLatitude` field
end
customFunction = function()
local myTerrain = Terrain.create();
myTerrain.generate();--this one probably needs `:` instead of `.`
--depends on actual code inside terrain.lua
end
end
do--MyScript.lua
myFunction= function()
return customFunction() --this line calls the global variable customFunction
end
end
Thus if your actual setup is similar to the one in question, then the "override" will take effect after the Custom.lua is executed and for all the subsequent calls to the Terrain.getLatitude regardless of whether or not they've called the file. (And any later file can override it again, and all calls after that will be using the new one)
It is probably more complicated to do a limited override in this setup. That again depends on the actual details of how your team has defined the Terrain class and the class system itself.

ovm printer casting error

I wanted to print out a structure used in a ovm_sequence_item. Since the structure is long, I plan to override table printer knobs by using tbl_printer.knobs.value_width = 100;
Here is the code snipper
virtual function void do_print(ovm_printer printer);
ovm_table_printer tbl_printer;
super.do_print(printer); //print all other fields
$cast(tbl_printer, printer);
tbl_printer.knobs.value_width = 100;
tbl_printer.print_generic("ppid","CppPpid_t",$bits(CppPpid_t),
$psprintf("A=%0b,B=%0b,C=%0d,D=%0d,E=%0d,F=%0x",
struct.A,
struct.B,
struct.C,
struct.D,
struct.E,
struct.F)
);
endfunction: do_print
I am getting this casting error.
Error-[DCF] Dynamic cast failed
*.sv, 58
Casting of source class type 'SIP_SHARED_LIB.ovm_pkg.ovm_tree_printer' to
destination class type 'SIP_SHARED_LIB.ovm_pkg.ovm_table_printer' failed due
to type mismatch.
Please ensure matching types for dynamic cast
Can someone help me what I am doing wrong? How is it getting ovm_tree_printer when I am trying to use ovm_printer?
ovm_printer is just the base class that declares the API for printers. What gets passed around are concrete classes, like ovm_table_printer or ovm_tree_printer. Both of these can be stored in a variable of type ovm_printer.
You're probably passing a tree printer in the print(...) call on your object. If you don't specify any printer, the default printer is used. Per default, this is the table printer, but it could be that this was changed. Look for ovm_default_printer in the package scope.
If someone explicitly wants you to do a tree print, then you can't magically change that to a table print. Best you can do is check if you're doing a table print and if so then change the knobs:
if (!$cast(tbl_printer, printer))
return;
tbl_printer.knobs.value_width = 100;

Cannot create class in AHK after destruction

I'm trying to wrap my head around classes in AHK. I'm C++ dev, so would like to make use of RAII (__New, __Delete), but it looks like I miss some concepts since things look very contra-intuitive for me.
After some tries I came up with this simple example:
class Scenario
{
__New()
{
MsgBox, NEW
}
__Delete()
{
MsgBox, DELETE
}
}
scenario := new Scenario
scenario := new Scenario
scenario := 1
scenario := {}
scenario := new Scenario
Return
As a result I get the following messages:
NEW
NEW
DELETE
DELETE
Questions:
Why doesn't the object get destroyed during the second assignment? I'd assume the number of refs going to 0, no?
How come I get 2 destructions in a row? Where was that object stored meanwhile? How could scenario variable hold both references?
Why was not the third construction called?
Why doesn't the object get destroyed during the second assignment?
Garbage collection had not been triggered yet
I'd assume the number of refs going to 0, no?
References going to 0 does not necessarily trigger GC
How come I get 2 destructions in a row?
Garbage collection cleaned both references at the same time
Where was that object stored meanwhile?
The heap
How could scenario variable hold both references?
scenario does not hold both references
Why was not the third construction called?
Only two Scenario objects are constructed. The variable scenario is a dynamic variable and is not always an instance of the class Scenario. The last assignment scenario := {} just creates an empty object.
Ok, found out what was missing. Two things:
AHK script is case-insensitive.
Since class is an object by itself in AHK it's possible to override the class by another object.
Here is a piece of the documentation:
Because the class is referenced via a variable, the class name cannot be used to both reference the class and create a separate variable (such as to hold an instance of the class) in the same context. For example, box := new Box would replace the class object in Box with an instance of itself. [v1.1.27+]: #Warn ClassOverwrite enables a warning to be shown at load time for each attempt to overwrite a class.
This explains what happened in the code above: variable name scenario is effectively the same as a class name Scenario, so I just quietly overrode my class with an empty object.
Also, since the new instance of the class is created before assignment, I got two 'NEW' in a row, only than 'DELETE'.

UVM- run test() in top block and Macros

I'm reading the following guide:
https://colorlesscube.com/uvm-guide-for-beginners/chapter-3-top-block/
In Code 3.2 line 24- run_test();
I realized that it supposed to execute the test, but how it know which test, and how, and why should I write it in the top block.
In Code 4.1 lines 11-14 (https://colorlesscube.com/uvm-guide-for-beginners/chapter-4-transactions-sequences-and-sequencers/):
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_field_int(inb, UVM_ALL_ON)
`uvm_field_int(out, UVM_ALL_ON)
`uvm_object_utils_end
Why should I add the "uvm_field_int" , what would happend if i didn't add them, and what is "UVM_ALL_ON"?
run_test is a helper global function , it calls the run_test function of the uvm_root class to run the test case. There are two ways by which you can pass the test name to the function.The first is via the function argument and the second is via a command line argument. The command line argument takes precedence over the test name passed via the function argument.
+UVM_TESTNAME=YOUR_TEST_NAME
run_test("YOUR_TEST_NAME");
run_test function in the uvm_root uses the factory mechanism to create the appropriate instance of the umm_test class and so the test case must register itself with the factory using the macro `uvm_component_utils for the factory mechanism (create_component_by_name) to function.
class YOUR_TEST_NAME extends umm_test ;
// register the class with the factory
// so that run_test can find this class when the
// string test_name is passed to it.
`uvm_component_utils(YOUR_TEST_NAME)
.....
endclass
The run_test function then kicks of the uvm_phases (..,build_phase,connect_phase,...) starting the uvm portion of the simulation. There should be no time ticks consumed before the run_phase starts , so it is essential that run_test case is called in the initial block itself. Also we want the uvm and test bench to be ready to drive and receive data as soon as the RTL is ready for which it is essential that we start the run_test at the earliest. Any delay in doing so will generate an error.
`uvm_field_int/uvm_field_object/.. are called field automation macros. They are not mandatory in the class definition and are provided as a helper macros to ease the use of many common/routine functions of the uvm_object. Examples of thse functions in uvm_object are - copy,compare,pack,unpack,print, etc and these macros generate code to automatically use these functions.
If you are not using the uvm_object common functions leaving out these macros from the class definition will not produce any errors.
In case you implement you own version of the common operations you can also leave out these macros from the class.
UVM_ALL_ON - enables all functions like compare/copy/... to be implemented for the particular field.
link with examples -
http://www.testbench.in/UT_04_UVM_TRANSACTION.html
For example the uvm_object has a compare function which compare two instances of the same class and return true if all the variables in the class are equal.
virtual function bit do_compare( uvm_object rhs, uvm_comparer comparer );
.....
// return 1 if all the variables match
return ( super.do_compare( rhs, comparer ) &&
this.var_1 == rhs.var_1 &&
this.var_2 == rhs.var_2 &&
......
this.var_n == rhs.var_n );
endfunction: do_compare
// use in main code
if ( new_class.compare(old_classs) )
...
//instead of
if ( new_class.var1 == old_class.var1 && new_class.var2 == old_class.var2 && ... new_class.varn == old_class.varn )
...
The above compare has to be written for each class and updated and maintained for every new variable that is added to the class. This could become error prone as newer variables are added. A similar process has to be followed for all the standard functions uvm_object provides.
The field automation macro generates function to address all these functionality automatically. So doing a do_print for a class with the macros will print out all the fields without explicitly writing any code for it.
// compare/print/.. functions for class simpleadder_transaction are provided by using `uvm_field_int macro.
`uvm_object_utils_begin(simpleadder_transaction)
`uvm_field_int(ina, UVM_ALL_ON)
`uvm_object_utils_end
BUT a word of caution , the use of these macros are discouraged as they add a significant amount of code into the class.. Most of these functions may not be needed by the class yet they get generated by default.
run_test is defined in the documentation (link) as:
virtual task run_test (
string test_name = ""
)
So, in principle, you can state there the test name as a string. But what's usually done is to pass it in the command line of your simulator using the argument: +UVM_TESTNAME=TEST_NAME
The uvm_object macros are a bit more complicated. They generate several methods and more importantly they register the object in the UVM factory, which is what makes them necessary (at least if you are using, as you should, the factory to create them). Citing from the UVM Class Reference documentation (Section 20.2 Component and Object Macros):
Simple (non-parameterized) objects use the uvm_object_utils* versions,
which do the following:
Implements get_type_name, which returns TYPE as a string
Implements create, which allocates an object of type TYPE by calling its constructor with no arguments. TYPE’s constructor, if
defined, must have default values on all it arguments.
Registers the TYPE with the factory, using the string TYPE as the factory lookup string for the type.
Implements the static get_type() method which returns a factory proxy object for the type.
Implements the virtual get_object_type() method which works just like the static get_type() method, but operates on an already
allocated object.

How can a Delphi TForm / TPersistent object calculate its own construction and deserialization time?

For performance tests I need a way to measure the time needed for a form to load its definition from the DFM. All existing forms inherit a custom form class.
To capture the current time, this base class needs overriden methods as "extension points":
start of the deserialization process
after the deserialization (can be implemented by overriding the Loaded procedure)
the moment just before the execution of the OnFormCreate event
So the log for TMyForm.Create(nil) could look like:
- 00.000 instance created
- 00.010 before deserialization
- 01.823 after deserialization
- 02.340 before OnFormCreate
Which TObject (or TComponent) methods are best suited? Maybe there are other extension points in the form creation process, please feel free to make suggestions.
Background: for some of our app forms which have a very basic structure (with some PageControls and QuantumGrids) I realized that it is not database access and other stuff in OnFormShow but the construction which took most of the time (around 2 seconds) which makes me wonder where this time is spent. As a reference object I will also build a mock form which has a similar structure but no code or datamodule connections and measure its creation time.
The best place for "instance created" is TObject.NewInstance.
In Delphi 2009 the best place for "before deserialization" is TCustomForm.InitializeNewForm. If that isn't available override TCustomForm.CreateNew and grab the time immediately before it returns.
You're correct that the best place for "after deserialization" is TComponent.Loaded.
For "before OnFormCreate" override TObject.AfterConstructor and get the time immediately before calling the inherited method. If you want the total construction time, grab the final time after that inherited call returns. That will include both the OnFormCreate and any initial activation time. Alternatively, you could just override TForm.DoCreate, if you're not overriding that anywhere else.
Let's assume that the loading of the form's DFM is the main time part of the construction of the form, we could add a constructor to the form like:
constructor TMyForm.Create( AOwner: TComponent );
var
S, E: Int64;
begin
QueryPerformanceCounter( S );
inherited Create( AOwner ); // here is the dfm loading
QueryPerformanceCounter( E );
// Log using the classname and the time in QPC ticks.
LogQPCTime( ClassName, E - S );
end;