How to persists variables from Erlang program initialization for use in other functions? - erlang

From what I've Googled, there are no global variables in Erlang?
Say I have function A (initialization code) which reads some info from a binary file into a few variables. I need to persist these variables for subsequent use in function B. Function B will be called many times whenever required.
What's the recommended practice for doing this?

Ih you are looping function B and there is no change of configuration, you could just pass the configuration arguments to function B.
If configuration could be changed or it is too much overhead, I usually store the configuration paramets in an ets table.
This is what I have also observed by other developers.
You can also check this short ets introduction by learnyousomeerlang.
function_B(Arg1, ConfigVars) ->
% do some stuff and modify Arg1
function_B(Arg1_Modified, ConfigVars).

Related

How does Dask handle external or global variables in function definitions?

If I have a function that depends on some global or other constant like the following:
x = 123
def f(partition):
return partition + x # note that x is defined outside this function
df = df.map_partitions(f)
Does this work? Or do I need to include the external variable, x, explicitly somehow?
Single process
If you're on a single machine and not using dask.distributed, then this doesn't matter. The variable x is present and doesn't need to be moved around
Distributed or multi-process
If we have to move the function between processes then we'll need to serialize that function into a bytestring. Dask uses the library cloudpickle to do this.
The cloudpickle library converts the Python function f into a bytes object in a way that captures the external variables in most settings. So one way to see if your function will work with Dask is to try to serialize it and then deserialize it on some other machine.
import cloudpickle
b = cloudpickle.dumps(f)
cloudpickle.loads(b) # you may want to try this on your other machine as well
How cloudpickle achieves this can be quite complex. You may want to look at their documentation.

Am I basically doing extra work by making my local functions global?

I read that it is faster and better to keep most of your functions local instead of global.
So I'm doing this:
input = require("input")
draw = require("draw")
And then in input.lua for example:
local tableOfFunctions = {isLetter = isLetter, numpadCheck = numpadCheck, isDigit = isDigit, toUpper = toUpper}
return tableOfFunctions
Where isLetter, numpadCheck etc are local functions for that file.
Then I call the functions like so:
input.isLetter(key)
Now, my question is: Am I reinventing the wheel with this? Aren't global functions stored in a lua table? I do like the way it looks with the input. before the function name, keeps it nice and tidy so I may keep it if it's not a bad coding practise.
Reinventing the wheels tailored to your personal needs is centerpiece of lua.
The method you describe is described as a valid one by lua creator himself in his book, here.
Everything in Lua is stored inside a table. The "faster" local function (as well as faster local variables) comes from the way of how globals and upvalues are looked up.
Below the line there's a quote of relevant part of more detailed explanation on speed that happened to occur in on game's forum.
Apart from that, locals are recommended due to cleanness of the code and error proofing.
In lua a table is created with {}, this operator reserves a certain amount of memory in the ram for the table. That reserved space stays constant and unmovable, exceptions are implementation details that script writer should not concern himself with.
Any variable you assign table to
a={};
b={ c={a} }
is just a pointer to the table in memory. A pointer takes up either 32 or 64 bits and that's it.
Whenever you pass table around only those 64 bits are copied.
Whenever you query a table in a table:
return b.c[1]
computer follows the pointer stored in b, finds a table object in ram, queries it for key "c", takes pointer to another table, queries that for key "1" then returns the pointer to the table a. Just a simple pointer hopping, workload on par with arithmetic.
Every function has associated table _ENV, any variable lookup
return a
is actually a query to that table
return _ENV.a
If the variable is local, it is stored in _ENV.
If there's no variable in _ENV with the given name, then global variables are queried, those actually reside in top-level table, the _ENV of the root function of the script (it is require or dofile function that loads and executes the script).
Usually, a link to the global table is stored in any other _ENV as _G. So the access to a global variable
return b
is actually something like
return _ENV.b or _ENV._G.b
Thus it is about 3 pointer jumps instead of 1.
Here is convoluted example that should give you an insight on the amount of work that implies:
%RUN THIS IN STANDALONE LUA INTERPRETER
local depth=100--how many pointers will be in a chain
local q={};--a table
local a={};--a start of pointer chain
local b=a; -- intermediate variable
for i=1,depth do b.a={} b=b.a end; --setup chain
local t=os.clock();
print(q)
print(os.clock()-t);--time of previous line execution
t=os.clock(); --start of pointer chain traversal
b=a
while b.a do b=b.a end
print(b)
print(os.clock()-t)--time of pointer traversal
When a pointer chain is about 100 elements, system load fluctuations may actually cause the second time be smaller. The direct access gets notably faster only when you change depth to thousands and more intermediate pointers.
Note that, whenever you query uninitialized variable, all 3 jumps are taken.
Globals are stored in the reserved table _G (the contents of which you can examine at any time), but it is good programming practice to avoid the use of globals.
Unless there is a very good reason not to, your table input should be local as well.
From Programming in Lua:
It is good programming style to use local variables whenever possible. Local variables help you avoid cluttering the global environment with unnecessary names. Moreover, the access to local variables is faster than to global ones.

What is the difference between "raw" dirty operations, and dirty operations within mnesia:async_transaction

What is the difference between a series of mnesia:dirty_ commands executed within a function passed to mnesia:async_dirty() and those very same transactions executed "raw"?
I.e., is there any difference between doing:
mnesia:dirty_write({table, Rec1}),
mnesia:dirty_write({table, Rec1}),
mnesia:dirty_write({table, Rec1})
and
F = fun() ->
mnesia:dirty_write({table, Rec1}),
mnesia:dirty_write({table, Rec1}),
mnesia:dirty_write({table, Rec1})
end,
mnesia:async_dirty(F)
Thanks
Lets first quote the Users' Guide on async_dirty context:
By passing the same "fun" as argument to the function mnesia:async_dirty(Fun [, Args]) it will be performed in dirty context. The function calls will be mapped to the corresponding dirty functions.This will still involve logging, replication and subscriptions but there will beno locking, local transaction storage or commit protocols involved. Checkpointretainers will be updated but will be updated "dirty". Thus, they will be updatedasynchronously. The functions will wait for the operation to be performed on one node but not the others. If the table resides locally no waiting will occur.
The two options you have provided will be executed the same way. However, when you execute the dirty functions out of the fun as in option one, each one is a separate call into mnesia. With async_dirty, the 3 calls will be bundled and mnesia will only wait until the 3 are completed on the local node to return. However, the behavior of these two may differ in a mnesia multi-node cluster. Do some tests :)

Rules about Lua state shutdown and garbage collection metamethods

tl;dr version: is a garbage collection metamethod safe during a Lua state shutdown if it accesses global variables? What about local up-values?
When a lua_State is closed with lua_close, the Lua documentation says that all of the objects are deleted. And it says that any associated garbage-collection metamethods are guaranteed to be called.
Great.
However, there are two possible use cases of GC metamethods that are uncertain under this paradigm:
What if you have a GC metamethod that uses a local variable that stores a collectable value. Say, a string, a function, etc. That is, your GC metamethod is defined as this:
local some_string = "string"
function mt:__gc() --[[Do something with some_string]] end
What happens in this case? Is it possible for some_string to be collected? I know that if the object the metatable is on is being collected under normal circumstances, then this isn't possible. Lua would guarantee that the value of some_string would remain until the GC function itself is collected.
But since all objects are being destroyed by lua_close, is it possible that upvalues of the GC function could be destroyed before the function is? I don't think it is (as this could cause all kinds of problems), but I'm looking for the real answer, not what I think.
I admit that it is unlikely that #1 will be a problem, as it would create many issues with GC metamethods. However, this is a completely different matter:
local some_string = "string"
function mt:__gc() print(some_string) end
This looks like #1, but it isn't. Why? Because it accesses a global variable. Namely, print.
There is no direct association between the function and whatever value is stored in print (unlike case 1, where some_string is clearly an upvalue of the function). As such, it is possible for print to be collected before calling the function during Lua state shutdown.
The question is this: is it safe for a garbage collection metamethod to ever use anything from the global table (ignoring the possibility of deliberate sabotage of the global table vis-a-vis print = nil) during Lua state shutdown? Or, as a general rule, should they always explicitly make any functions or data they touch local? Will that be sufficient to avoid problems?
Any data that is accessible from the __gc method is safe to access; this includes both locals and the tables that are accessible, like _G, which contains print.
What can be a problem are (un-)loaded C libraries; this affects Lua 5.1, and is fixed in Lua 5.2.1. See the patch for "Finalizers may call functions from a dynamic library after the library has been unloaded".

Is a z/OS PL/I CONTROLLED variable preserved between separate invocations of a procedure?

Is a z/OS PL/I CONTROLLED variable preserved between separate invocations of a procedure? Let’s suppose that we need a counter that is internal to a subroutine and preserved across invocations. The easiest way to do it would be to use a static variable initialized to zero and incremented on each entry to the subroutine. But you can’t do that if the program has to be reentrant. So the question is whether we have access to a controlled variable that was allocated in a previous call. Would the following code work?
PROC1: PROCEDURE OPTIONS(MAIN);
...
CALL A;
...
A: PROCEDURE;
DECLARE COUNT CONTROLLED ALIGNED FIXED BIN(15);
IF (ALLOCATION(COUNT) = 0)
THEN ALLOCATE COUNT INIT(1);
ELSE COUNT = COUNT + 1;
...
END A;
END PROC1;
According to the PL/I Language Reference, after you ALLOCATE a variable, you do not need to FREE it (though that is generally good practice), and “All controlled storage is freed at the end of the program.” It doesn’t say that storage is freed at the end of the block.
The PL/I Programming Guide provides some clues in the chapter Using PLIDUMP in the Locating Controlled Variables section, but it is not definitive. It says that the key to locating a controlled variable is to find its anchor. With NORENT WRITABLE there is an anchor in static storage. With NORENT NOWRITABLE(FWS) there is an address to an anchor automatic storage. (There is an extra level of indirection.) With NORENT NOWRITABLE(PRV) there appears to be a static table with an offset into a private table for each controlled variable. In other words, depending on the processing options, maybe the variable is accessible, and maybe it isn’t. It doesn’t say anything about using the RENT option.
Any thoughts?
As per the PL/I Programming Guide compile time option "RENT", Your code is "naturally reentrant" if it does not alter any of its static variables.
The RENT option specifies that the compiler is to take code that is not naturally reentrant and make it reentrant.
Thus, you can increment STATIC variable on each entry to subroutine if the program is compiled with RENT option.
Please refer to this link => Rent Option from PL/I Programming Guide
As per "PL/I Structured Programming" by J.K. Hughes, A REENTRANT procedure may be called by other procedures asynchronously. For example task B invokes SQRT function. While this function is in process of computing square root, task A (having higher execution priority than task B) needs to gain control of the system and use SQRT function. The SQRT function is interrupted and intermediate results for task B saved; then task A uses SQRT function.
When task A completes its execution, control is returned to task B at the point where it was interrupted. Then, task B completes its use of SQRT function.

Resources