I am currently learning Cobol language, and I wrote a paragraph with the following structure :
MYPARA.
EVALUATE TRUE
WHEN COND1
...
WHEN COND2
...
PERFORM MYPARA
WHEN OTHER
...
END-EVALUATE
.
This is a recursion that works great, however I just learned that it must not be done because it can lead to unpredictable results ( In COBOL, is it possible to recursively call a paragraph? ). So is it impossible to have recursion within the same Cobol program ?
I thought about using an intermediary paragraph : MYPARA execute MYPARA2 and MYPARA2 execute MYPARA. Is it exactly the same or different for the compiler/execution ?
The execution works great, but it is clearly stated that a paragraph can't call itself. Any form of recursion between paragraph is possible or forbidden ?
In my case I could wrap the EVALUATE in a PERFORM UNTIL as an alternative to the recursion, but I really wanted to do it that way.
Recursion works for most languages and COBOL programs because the return location is pushed onto a stack before the call. When the program executes itself, a new return location is pushed. As each invocation of the program returns, the locations stored on the stack are popped off one-by-one, allowing the return instruction to resume execution at the right places.
For IBM COBOL, the Perform statement does not use a stack. Instead, each performed paragraph has a "resume" address for the end of the paragraph. Normally, this resume address points to the next paragraph. Each Perform statement has a "save" cell to save the target paragraph's resume address. When the perform happens, it copies the resume cell to the save cell, stores the address after the perform statement in the resume cell, then jumps to the paragraph. The end of the paragraph picks up the address in the resume cell and jumps to it, effectively returning to the address after the perform. The instructions there copies the save cell back to the resume cell, restoring the paragraph to the way it was.
This all works great until you realize that the "save" cell is a stack with the capacity of only one entry. This means if the same save cell is used again before a restore happens, the old value is wiped out. The resume cell will never have its old content back. The paragraph will not be able to return to where it supposed to return. The problem may not show up if overwriting does not occur because each perform statement has its own "save" cell. Thus, if we use "->" to represent "performs" and A & B are paragraphs, A->B->B works, but A->B->B->B will get you into an infinite loop when the outermost B is trying to return to A.
Related
My painful hunt for this feature is fully described in disgustingly log question: Several last offsets aren't getting commited with reactive kafka and it shows my multiple attemps with different failures.
How would one subscribe to ReactiveKafkaConsumerTemplate<String, String>, which will process the records in synchronous way (for simplicity), and will ack/commit every 2s AND upon manual cancellation of stream? Ie. it works, ack/commits every 2s. Then via rest/jmx/whatever comes signal, the stream terminates and ack/commits the last processed kafka record.
After a lot of attempts I was able to come up with following solution. It seems to work, but it's kinda ugly, because it's very "white-box" where outer flow highly depends on stuff happening inside of other methods. Please criticise and suggest improvements. Thanks.
kafkaReceiver.receive()
.flatMapSequential(receivedKafkaRecord -> processKafkaRecord(receivedKafkaRecord), 16)
.takeWhile(e-> !stopped)
.sample(configuration.getKafkaConfiguration().getCommitInterval())
.concatMap(offset -> {
log.debug("ack/commit offset {}", offset.offset());
offset.acknowledge();
return offset.commit();
})
.doOnTerminate(()-> log.info("stopped."));
What didn't work:
A) you cannot use Disposable.dispose, since that would break the stream and your latest processed record won't be committed.
B) you cannot put take on top of stream, as that would cancel the stream and you won't be able to commit either.
C) not sure how I'd be able to intercorporate usage of errors here.
Because of what didn't work stream termination is triggered by boolean field named stopped, which can be set anyhow.
Flow explained:
flatMapSequential — because of inner parallelism and necessity to commit N only if all N-1 was processed.
processKafkaRecord returns Mono<ReceiverOffset>, ie. the offset of processed record to have something to ack/commit. When stopped the method will skip processing and return Mono.empty
take will stop stream if stopped, this has to be put here becaue of possibility of whole sample interval consisting only from "empties"
rest is simple: sample by given interval, commit in order. If sample does return empty record, commit is skipped. Finally we log that stream is cancelled.
If anyone know how to improve, please criticise.
I need some help understanding transaction scoping for procedures/programs outside the current program.
Suppose I've three program, program A, program B and program C. Inside program A, I've a procedure that has some lines in it wrapped inside a do transaction (not strongly typed) block. Within that do transaction block, it calls another Program B. Upon return from program B there is an undo, leave command. Within the same transaction block, it calls program C and has an undo, leave after this call too.
My question is, if within the transaction block, program B executes without errors, but program c returned an error, will the undo,leave after program C call will also undo transactions that happened inside program B?
Procedure do_something:
some processing....
do transaction:
error-message = "".
{run programB.p}
if error-message <> "" then undo, leave.
some further processing...
error-message = "".
{run programC.p}
if error-message <> "" then undo, leave.
end. /* end of do transaction */
end procedure.
Yes. In the example that you describe everything gets rolled back.
It is not so much that it is "extended" per se but just that the transaction includes everything that happens in that session from the point in time when it is enabled all the way until it is either committed or rolled back. Internal procedures, external procedures, user defined functions, methods of classes, trigger code etc.
"In that session" is important - if you call a procedure on an app server that activity is NOT included since it is its own process with its own distinct transaction context.
When app servers are involved things get messy. The original caller has no (built-in) capability to know what to roll back in the called app server session. The app server call could return an error that causes the caller to roll back if it encounters problems but the caller could also decide to trap and ignore that error.
Yes. Everything happening in the transaction block will be undone.
I'm stuck on something in my Robot Framework project. When I hit a button from the 1st page after the login is done, another tab is opened, however, sometimes, the new window is not loaded and the code (robotframework) keep waiting for an answer.
To avoid getting an error when this situation happens, I want to solve it while the code still running, I want to know if there is any keyword that applies an action in case something is not done within a given lead time. In my case it would be to close the new window and repeat the previous step (hit the button from the first page again), therefore, it would be 2 actions in case the actions fails (lead time).
I have tried to use the keyword Run Keyword and Return Status, in my case the status would be false, however, since my code is kept waiting for an answer, the status is always True, therefore, it does not work for me.
I have read that there is a keyword named Run Keyword If Timeout Occurred however, it can be only used on Teardown`, therefore, I also don't know if it can applied.
I see you are trying to compare Boolean and String.
it's should be boolean and boolean run Keyword if ${status}==False.
On this site containing the documentation describing how make reads a Makefile, there is the following paragraph:
[...]
It’s important to understand this two-phase approach because it has a direct impact on how variable and function expansion happens; this is often a source of some confusion when writing makefiles. Here we will present a summary of the phases in which expansion happens for different constructs within the makefile. We say that expansion is immediate if it happens during the first phase: in this case make will expand any variables or functions in that section of a construct as the makefile is parsed. We say that expansion is deferred if expansion is not performed immediately. Expansion of a deferred construct is not performed until either the construct appears later in an immediate context, or until the second phase.
[...]
I do not know what the highlighted part means.
Does it try to say that if there is a variable reference first found in a deferred section it will not be expanded during the first phase, but if the same variable reference is then found (later in the Makefile) in an immediate context, that variable reference will be expanded? Why would it say this explicitly?
Or does it try to say that there are cases when the exact same line can be read within a different context?
I do not know what the highlighted part means.
Does it try to say that if there is a variable reference first found
in a deferred section it will not be expanded during the first phase,
but if the same variable reference is then found (later in the
Makefile) in an immediate context, that variable reference will be
expanded?
Something like this, but I hesitate to say "yes" because I'm not sure I fully understand you. Instead, I put it in my own words: the manual says that an expression with a deferred expansion is expanded immediately when it is evaluated as part of the value of an expression that is immediately expanded. Example:
INTRO := The messages are
DEFERRED = $(MESSAGE1) literal message
IMMEDIATE := $(INTRO) $(DEFERRED)
MESSAGE1 = deferred message,
demo:
#echo immediate: "$(IMMEDIATE)"
#echo deferred: "$(INTRO) $(DEFERRED)"
Demo:
$ make demo
immediate: The messages are literal message
deferred: The messages are deferred message, literal message
$
Note that variable DEFERRED is expanded immediately as part of the process of setting the value of immediately-expanded variable IMMEDIATE. You can see this from the difference in the output of the two echo commands. You can also see that this expansion does not stick to DEFERRED, which is one of the things that can be confusing.
Why would it say this explicitly?
Because one might suppose otherwise. Specifically, one might suppose that building the "demo" target in the example above would cause two identical lines to be printed. That would require a deferred expansion of DEFERRED being somehow symbolically encoded into the immediate expansion of IMMEDIATE, or else that DEFERRED be somehow converted into an immediately-expanded variable. Nothing along those lines happens.
Note, too, that the two expansions of DEFERRED are different in this case, which is not necessarily a possibility that is immediately evident.
Or does it try to say that there are cases when the exact same line
can be read within a different context?
Inasmuch as I differentiate between identical and exact same, the only way "the exact same" line can be evaluated in different contexts is if it is part of the expansion of a deferred-expansion expression. Then it can appear in both immediate and deferred context, as the text $(MESSAGE1) literal message in the example does. In that sense, yes, the manual is talking about that; it's not different from your other alternative.
It is also possible for distinct but identical text to appear in different contexts, but this is not as interesting.
I have a doubt about Ada, and in particular about the select statement when used in conjunction with a protected entry. Let's consider the following code fragment:
select
Protected_Object.Some_Entry;
else
DoSomethingElse;
end select;
My question is simple: when the select statement is reached, what happens? In particular, what I want to know is: does the else branch get chosen only if Some_Entry's guard is closed or does it get chosen even if the guard is opened but the entry is "occupied" (ie: there's already a call to Some_Entry executing) and thus cannot be called immediately??
I believe that the else branch is chosen only if the entry's guard is closed (i.e. the barrier condition is false). The sequence of events for a protected entry call is given by RM 9.5.3(8):
A new protected action is started on the object.
The named entry is checked to see if it is open (i.e. the barrier condition is true); if open, the entry call is said to be selected immediately, and then the entry body is executed.
Starting a protected action may involve a short delay if another task is performing a protected action on the same object (9.5.1(4)). However, the intent is that this delay is always very short. If a protected subprogram or entry does anything that could block the program, this is considered an error (9.5.1(8-18)). Thus, waiting until another task releases a protected object is supposed to be a very short wait if at all; on a multi-processor system, it's perfectly acceptable to implement this wait by spinning (essentially while Protected_Object_Is_In_Use(Obj) loop null; end loop;) as opposed to waiting on a queue.
Thus, my reading of 9.5.3(8) is that the definition of "selected immediately" does not take into account the short wait needed if another task is engaged in a protected action on the object. If the task has to wait, it does so. If, once it is able to grab the object, it finds that the barrier is true, then the entry is "selected immediately". This may not quite fit our idea of what the English word "immediately" means, but it's how the term is defined.
Thus, for a conditional entry call, RM 9.7.3 says that the entry call is cancelled (and the else branch executed) if it is not selected immediately. Using the definition in 9.5.3(8), this means that the else branch is executed only if the barrier condition is false (after the task succeeds in grabbing the protected object).
The 'else' branch is chosen if Some_Entry is not immediately accessible (either because there is already another task accessing the protected object, or because the guard prevents calling the entry in the first place.
The goal of the 'else' branch is basically that your task does not stay blocked and thus might miss a timeout or an action to execute on a regular schedule. So when you use 'else', the select statement cannot be blocking (unless of course the entry itself, once called, takes forever).
Edit: As demonstrated below by #simonwright, this answer is incorrect: the 'else' branch is taken when the guard is False, otherwise the task will block on the protected object's entry. By design, such entries should perform their work in a very limited amount of time.