Progress 4gl - shared procedures - progress-4gl

Am working in Progress 4gl and am an novice programmer. I am working on a situation where there are five procedures (.p files) which are not related to each other, sharing a single procedure (.p file).
My issue is that i need to modify the shared procedure , that should have its effect on only one calling procedure and not the other four. What are the ways that i can link these two procedures at the same time preventing the effects on other four procedures.
Pls , help me with this issue. And sorry if am not clear

The simple, but architecturally repugnant, solution is to use a global shared variable.
Many people will tell you that this is a bad coding technique. They are right. But you aren't asking for advice on best practices.
Simply create such a variable in both the caller and the callee. Procedures that don't need it won't miss it.
One of your "normal" programs:
/* p1.p */
message "p1, I'm normal.".
run common.p.
Your "special" program:
/* p2.p */
define new global shared variable special as character no-undo.
message "p2, I'm special!".
run common.p.
message "special = " special.
The common program:
/* common.p */
define new global shared variable special as character no-undo.
message "common stuff...".
if program-name(2) = "p2.p" then special = "special value".
return.
You can define a NEW GLOBAL SHARED variable as many times as you like and you only get one copy of it. The "new" doesn't overwrite any existing variables (if you leave out GLOBAL it behaves differently).
You didn't ask for it and maybe you don't need it but the program-name(2) check peeks at the call stack to see if common.p was called by p2.p.
There are other, more complicated ways to do this but they all boil down to the same problem -- you're creating the basis for some very ugly coupling between your "special" program and the now no longer generic "common" program.

The best way is to add a "flag" to the shared procedure, and then pass a flag when you need different behavior. You don't want to change the shared procedure so it needs to know what program is calling it.

Move all logic of the procedure to a new one that has an input
parameter.
Call that procedure from the original .p
Call the new procedure from the procedure that needs the extra parameter.
Optional
Gradually replace all runs of original.p to new.p
Remove original.p once you're sure all runs have been changed.
Depending on your OpenEdge version you could move the logic to a class instead of a procedure. In the class you can use overloading

Related

Is there a way to perform a procedure in netlogo knowing only it's name?

I am developing a netlogo extension and I want to add a command where the user will tell me a list of procedures names that have no parameters.
Later I will perform this procedures but the only thing I will know is the name of the procedure that was passed to me before.
The command that the user will use to inform the name of the procedures is the following:
qlearningextension:actions ["procedure1" "procedure2" "procedure3"]
Later the extension will perform this procedures. I want to know if there is a way to get a procedure with only having it's name.
My recommendation would be to change the syntax of your primitive from taking in a list of strings to taking in a repeatable number of anonymous commands. You can do this by setting the syntax to CommandType | RepeatableType. A good reference should be the ControlFlow extension (cf) which uses a similar technique to accept at least 1, but possibly many, boolean/command combinations for its variadic cf:iflese primitive.
The anonymous commands provided will be checked for correctness at compile time, meaning you won't have to rely on the extension user properly typing the name of the procedures or forgetting if they change a name. The commands will also be easily executable by your extension prim at runtime, you won't have to "search" for the right procedure to execute (again, see the cf example).
Users of your extension will need to wrap your prim in parens when using the "more than 1" repeatable syntax: (qlearningextension:actions [procedure1] [procedure2] [procedure3])

Exploit Matlab copy-on-write by ensuring function arguments are read-only?

Background
I'm planning to create a large number of Matlab table objects once, so that I can quickly refer to their contents repeatedly. My understanding is that each table variable/column is treated in copy-on-write manner. That is, if a table column is not modified by a function, then a new copy is not created.
From what I recall of C++ as of 1.5 decades ago, I could ensure that the code for a function does not modify its argument's data by using constant-correctness formalism.
The specific question
I am not using C++ in these days, but I would like to achieve a similar effect of ensuring that the code for my Matlab function doesn't change the data for selected arguments, either inadvertently or otherwise. Does anyone know of a nonburensome way to do this, or just as importantly, whether this is an unrealistic expectation?
I am using R2015b.
P.S. I've web searched and came across various relevant articles, e.g.:
http://www.mathworks.com/matlabcentral/answers/359410-is-it-possible-to-avoid-copy-on-write-behavior-in-functions-yet
http://blogs.mathworks.com/loren/2007/03/22/in-place-operations-on-data
(which I need clarification on to fully understand, but it isn't my priority just now)
However, I don't believe that I am prematurely optimizing. I know that I don't want to modify the tables. I just need a way to enforce that without having to go through contortions like creating a wrapper class.
I've posted this at:
* Stack Overflow
* Google groups
There is no way of making variables constants in MATLAB, except by creating a class with a constant (and static?) member variable. But even then you can do:
t = const_table_class.table;
t(1,1) = 0; % Created and modified a copy!
The reason that a function does not need to mark its inputs as const is because arguments are always passed by value. So a local modification does not modify data in the caller’s workspace. const is something that just doesn’t exist in the MATLAB language.
On the other hand, you can be certain that your data will not be modified by any of the functions you call. Thus, as long as the function that owns the tables does not modify them, they will remain constant. Any function you pass these tables to, if they attempt to modify them, they will create a local copy to be modified. This is only locally a problem. The memory used up by this copy will be freed upon function exit. It will be a bug in the function, but not affect code outside this function.
You can define a handle class that contains a table as it's preperty. Define a property set listener that triggers and generates error/warning when the value of the property changes.
classdef WarningTable < handle
properties (SetObservable)
t
end
methods
function obj = WarningTable(varargin)
obj.t = table(varargin);
addlistener(obj,'t','PreSet',...
#(a,b)warning('table changed!'));
end
end
end
This should generate warning:
mytable = WarningTable;
mytable.t(1,1) = 0;

MATLAB: overriding table() methods

SETUP Win7 64b, R2015b, 16 GB of RAM, CPU i7-2700
The table() is a fundamental Matlab class which is also sealed, hence I cannot subclass it.
I want to fix some methods of this class and add new ones.
For instance, table.disp() is fundamentally broken, e.g. try NOT disp(table(rand(1e7,1))), or forget the ; in the command window. The variable takes only 76 MB in RAM but the display is unbuffered and it will stall your system!
Can I override methods like table.disp() without writing into matlabroot\toolbox\matlab\datatypes\#table?
Can I extend the table class with a new method under C:\MATLAB\#table\ismatrixlike.m? Why do I get
ismatrixlike(table)
Undefined function 'ismatrixlike' for input arguments of type 'table'.
Obviously, I did
addpath C:\MATLAB\
rehash toolboxcache
I also tried clear all.
The path has (alphabetic) precedence over matlabroot, but is missing a table.m class definition. If I add the native class defition to C:\MATLAB\#table, then I can run my new method (after a clear all). However:
>> methods(table)
Methods for class table:
classVarNames ismatrixlike table varfun
convertColumn renameVarNames unstack
only lists the methods in the new \#table folder, even though (some of) the old methods still work, e.g.
size(table)
This partly solves the problem, since now, the native \#table\private folder is not accessible anymore and therefore many native methods are broken!
Why am I doing this? Because I do not want to wait another 2 years before the table() is fixed. I already lost entire days because I simply forgot a ; in the command window and I cannot force a restart on my pc if it is running multiday simulations, but I have to wait for the disk-swap to end :(.
APPENDIX
More context about disp(table(rand(1e7,1))). This is what happens when I hit it (and luckily I am fast enough to CTRL-C out of it):
The culprit is line 172 of table.disp() which converts the numeric array into a cellstring (with the padding too!):
[cells, err, isLeft] = sprintfc(f, x, b);
After experimenting with several alternatives, I adopted the solution that intereferes the least with Matlab's native #table implementation and it's easily removed if things go awry.
The solution:
copy the whole #table folder, i.e. fullfile(matlabroot,'toolbox','matlab','datatypes','#table'), into a destination where you have write permissions.
I picked the destination to be fullfile(matlabroot,'toolbox','local','myfiles') since I do not have to bother with OS cross-compatibility, i.e. matlabroot takes care of that for me.
paste into the destination your #table folder with the new, overloaded and overriding methods (partially overwriting the copied original files)
add the destination to the matlab path, before the original #table, e.g. addpath your_destination -begin
Effects, pros and cons:
The native #table class/methods are now shadowed, try e.g. which table -all. However, this effect is quite clear, easily detectable and easily removed (delete destintation and remove path);
No weird conflicts between native #table (now shadowed) and new #table;
All methods, new and old, are visible, try methods(table);
Private table methods are accessible...
... but you are forced to use them.
Exposing the new methods (user-implemented) to the private ones requires more maintenance and direct handling of version conflicts in the table implementations.
You need write permissions on some eligible destination.
For those interested about the details, you can look into, https://github.com/okomarov/tableutils. Specifically the install_tableutils (the readme might not be updated).
The following works for me:
Define a modified disp function, say disp_modified.m, as follows, and put it in your path:
function disp_modified(t)
if istable(t)
%// Do whatever you want to display tables
builtin('disp', '''disp'' function intercepted!')
else
%// For non-tables, call `disp` normally
builtin('disp', t)
end
Define disp as a function handle to the modifed function (you can do that in startup.m to always have it by default):
disp = #disp_modified;
After this, in the command window I get
>> disp(1:5)
1 2 3 4 5
>> disp({1 2 3 'bb'})
[1] [2] [3] 'bb'
>> disp(table(rand(1e3,1)))
'disp' function intercepted!
Depending on the usage of the new class perhaps you could follow a cleaner approach. The proposed approach described in your post has the drawback that perhaps code used in your updated environment would not be easily portable to a new environment, or a program executed in your environment may demonstrate different behavior in a different environment.
Some questions you could consider (and perhaps clarify) would be: How do you intend to use the new class? Do you want to replace all the existing table uses? Do you want to be able to use it instead of a table class argument? Or do you want to alter the table so that each usage of the original table class in your environment uses the new class.
If you just need a new improved table for your usage, you could consider encapsulating the original table class in a new class. E.g MyTable, delegate all the methods you do not need to the original table methods, replace the methods you would like to improve or add new ones.
Update: Just saw the complete solution in Github and understood what you intended to do. Nice work. I will leave the post in case anyone finds it useful.

Best way to return values to calling program from Drools 6 rules?

My rules in a drl file will return 1 or more String values back to the calling program.
Right now the way I do that is via global variables as below
global java.util.List<String> statuses;
The calling program will pass it an empty ArrayList() and within my rules, I'll add the String values into the List. Finally, my calling program will retrieve the statuses list that might contain zero or many String items in the list as below
session.getGlobal("statuses")
But in the drools user guide, it said that it's not recommended that rules should change values of the global variables.
Are global variables the best way to return values back to the calling program? If not, what's the best way please? I have to deal with concurrency in my web application as well so I'm looking for the best way to return values back to the calling program for concurrency as well.
Thanks
There is nothing wrong with changing the value of a global variable in the code within the consequence ("right hand side") of a rule. What you describe is one of standard use cases for globals.
What the author of the Drools user guide (please add the exact reference!) meant is that changes of a global that is used in the condition ("left hand side") of a rule are not considered in the (re-)evaluation of these conditions. Therefore, this is to be avoided.
As for concurrency: Use a properly synchronized List object as a global.

lua - capturing variable assignments

Ruby has this very interesting functionality in which when you create a class with 'Class.new' and assign it to a constant (uppercase), the language "magically" sets up the name of the class so it matches the constant.
# This is ruby code
MyRubyClass = Class.new(SuperClass)
puts MyRubyClass.name # "MyRubyClass"
It seems ruby "captures" the assignment and inserts sets the name on the anonymous class.
I'd like to know if there's a way to do something similar in Lua.
I've implemented my own class system, but for it to work I've got to specify the same name twice:
-- This is Lua code
MyLuaClass = class('MyLuaClass', SuperClass)
print(MyLuaClass.name) -- MyLuaClass
I'd like to get rid of that 'MyLuaClass' string. Is there any way to do this in Lua?
When assigning to global variables you can set a __newindex metamethod for the table of globals to catch assignments of class variables and do whatever is needed.
You can eliminate one of the mentions of MyLuaClass...
> function class(name,superclass) _G[name] = {superclass=superclass} end
> class('MyLuaClass',33)
> =MyLuaClass
table: 0x10010b900
> =MyLuaClass.superclass
33
>
Not really. Lua is not an object-orientated language. It can behave like one sometimes. But far from every time. Classes are not special values in Lua. A table has the value you put in it, no more. The best you can do is manually set the key in _G from the class function and eliminate having to take the return value.
I guess that if it REALLY, REALLY bothers you, you could use debug.traceback(), get a stack trace, find the calling file, and parse it to find the variable name. Then set that. But that's more than a little overkill.
With respect at least to Lua 5.2: You can capture assignments to A) the global table of a Lua State, as mentioned in a previous reply, and also B) to any other Lua Object whose __index and __newindex metamethods have been substituted (by replacing the metatable), this I can confirm as I'm currently using both these techniques to hook and redirect assignments made by Lua scripts to external C/C++ resource management.
There is a gotcha with regards to reading them back though, the trick is to NOT let the values be set in a Lua State.
As soon as they exist there, your hooks will fail to be called, so if you want to go down this path, you need to capture ALL get/set attempts, and NEVER store the values in a Lua State.