Andre White wrote:
> Hi Keith thanks for your explanation. For point number 1 clear already.
>
> if not ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
> atm.ncr.txn_stat := expect_tran_l;
>
> For point number 2 i'am not agree with you (Don't change atm.ncr.txn_stat at the beginning), so you mean I must put the same condition with in case tran_cancel_shutdown_atm_rc
>
> DEFINE atm_is_faulted = BNA_FAULTY and CASH_HANDLER_FAULTY and CARD_RDR_FAULY #;
>
> INT PROC BNA_FAULTY;
> BEGIN
> ...........
> ............
> ............
> RETURN TRUE
> END;
> ==================
> INT PROC CASH_HANDLER_FAULTY;
> BEGIN
> ...........
> ............
> ............
> RETURN TRUE
> END;
> =============
> INT PROC CARD_RDR_FAULTY;
> BEGIN
> ...........
> ............
> ............
> RETURN TRUE
> END;
>
>
> My point to create a new variable just save value atm.ncr.txn_stat and store back in case tran_cancel_shutdown_atm_rc and atm_is_faulted.
>
> if i have declaration like this :
>
>
> int a := c; ! c values 2!
>
> My Question ?
>
> 1. possible for value a is equal 1 or 3 or 4 after i assign 2 ? if possible give me example ?
> 2. First call atm_is_faulted
> |
> v
> if not ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
> atm.ncr.txn_stat := expect_tran_l;
>
> case atm.ncr.txn_resp_cde of
> begin
> shutdown_atm_rc ->
> begin
> .....
> end;
> tran_cancel_shutdown_atm_rc ->
> begin
> ! second call atm_is_faulted !
> ! | !
> ! v !
> if atm_is_faulted then
> begin
> call send_faulty_screen;
> return;
> end;
> ..........
> end;
> ....................
> end;
> END ;
>
> what the different if make like this :
>
> if ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
> begin
> call send_faulty_screen;
> return;
> end;
>
> atm.ncr.txn_stat := expect_tran_l;
> case atm.ncr.txn_resp_cde of
> begin
> shutdown_atm_rc ->
> begin
> .....
> end;
> tran_cancel_shutdown_atm_rc ->
> begin
> if atm_is_faulted then
> begin
> call send_faulty_screen;
> return;
> end;
> ..........
> end;
> ....................
> end;
> END ;
>
> Thanks Keith
Hi Andre,
Your most recent post is a little confusing to me. I guess English is not your first language, so maybe my explanations are a little difficult for you to understand, and maybe I confused you. It is hard enough to discuss programming options in natural language, even when the two people have the same natural language as their first language. Trying to understand a discussion in a second language must be very difficult.
Let me summarize what I was trying to say in my previous post, in case that helps you understand anything that was confusing.
I first explained the problem you still had with calculating the length of the IFILEINFO_RESULT structure.
I then pointed out possible problems with closing the file when you found it was format 1 and opening it again with 32-bit keys.
I then wrote about your question about how to deal with getting the right value stored into atm.ncr.txn_stat -- you had one idea about how to do it and your friend had a different idea about how to do it. I described three general approaches that might be used for situations like the one I think your code represents. I discussed a little bit about benefits and drawbacks of each of those approaches. Then I said that in this particular program, I thought that your idea about how to do it was probably the best choice. In other words, what you labeled "MY CHANGES" is what I believe probably is the best choice, given what you have told me about the program.
I then went on to say that although I advised against the approach your friend suggested, if you ended up using his approach, I saw two bugs in his code, and showed how to correct them. I do not suggest using your friend's approach, but if you do decide to use it, you need to make those corrections.
Finally, I thanked you for thinking of explaining how atm_is_faulted was defined. I pointed out that you probably did not mean to say it contained three CALL statements. And I said that we probably did not have to discuss the details of atm_is_faulted, since it probably did not affect the question you had asked about the best way to deal with updating the value of atm.ncr.txn_stat.
Okay, now let me try to respond to your most recent post.
I think that when you said that point number 1 is clear now, you mean that you understand my explanation of why your calculation of the size of the IFILEINFO_RESULT structure was wrong and how to do it safely with $LEN, so we don't have to talk about that any more.
Or by point 1, did you mean my correction of your friend's addition to the program? That correction was:
if not ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
atm.ncr.txn_stat := expect_tran_l;
If point 1 was this correction, do you still need to discuss the size of IFILEINFO_RESULT structure? Or do you now understand what I was saying about the size of the IFILEINFO_RESULT structure?
I am not sure what you mean when you start to talk about my point 2. I'm not sure what you feel is my point 2. I did not number my points, which is part of what makes me unsure what you mean. My suggestion was that your suggestion, what you labeled "MY CHANGES", probably is the best choice. You now seem to be asking about the approach your friend suggested. That approach could be used, but I believe it is not the best approach to use.
The reason I believe your friend's approach is not the best is that it requires that the condition in the "if" statement gets the same result as is implied by the case statement and the "if" statement within the tran_cancel_shutdown_atm_rc case. Duplicating logic in that way usually is a bad idea. The fact that your friend got that condition wrong illustrates one reason why it usually is a bad idea.
So, again, I think your approach is right: at the beginning save atm.ncr.txn_stat in a temp variable and set atm.ncr.txn_stat to expect_tran_l, then inside the case statement, set atm.ncr.txn_stat back to the value you saved in the temp variable. Just as you wrote it in your earlier post.
You then asked two questions.
1. possible for value a is equal 1 or 3 or 4 after i assign 2 ? if possible give me example ?
I'm not sure what motivates you to ask this question, but if I understand the question correctly, here is the answer: If the variable "a" is not intentionally changed as a side-effect of calling any of the other procs in your code, and if none of your code accidently stores outside the memory area of your other variables, then once you set "a" to 2, "a" will remain having the value 2 until you store some other value into "a".
2. First call atm_is_faulted
|
v
if not ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
atm.ncr.txn_stat := expect_tran_l;
case atm.ncr.txn_resp_cde of
begin
shutdown_atm_rc ->
begin
.....
end;
tran_cancel_shutdown_atm_rc ->
begin
! second call atm_is_faulted !
! | !
! v !
if atm_is_faulted then
begin
call send_faulty_screen;
return;
end;
..........
end;
....................
end;
END ;
what the different if make like this :
if ( atm_is_faulted and atm.ncr.txn_resp_cde = tran_cancel_shutdown_atm_rc) then
begin
call send_faulty_screen;
return;
end;
atm.ncr.txn_stat := expect_tran_l;
case atm.ncr.txn_resp_cde of
begin
shutdown_atm_rc ->
begin
.....
end;
tran_cancel_shutdown_atm_rc ->
begin
if atm_is_faulted then
begin
call send_faulty_screen; <----- will never be executed
return; <----- will never be executed
end;
..........
end;
....................
end;
END ;
My answer: The second form of the code in this question will do the same as the first form, but is more complicated and contains some code that will never be executed (the two lines I marked "<----- will never be executed"). Those lines will never be executed because the return statement in the "if" statement at the beginning of the code will cause the code to exit at that point, so the conditions that would let the case statement get to the two lines I marked will never be true when the case statement executes.
Code like this is complicated to follow precisely because of interactions between parts of the code. In a situation like this, where you have a variable such as atm.ncr.txn_resp_cde that identifies several states in which you do different things, putting everything into a single case statement usually is much easier to follow when you read the code later than it is when you have multiple tests at different points through the code. Also, having early returns from a section of code is something to be avoided if possible, since there might be something done below that return statement that you will assume gets done, but it gets skipped because of the early return. I do not know enough about this program to tell whether you can eliminate the early return from the tran_cancel_shutdown_atm_rc case, but it would be desirable to eliminate it.
Just to be clear, I believe your original suggestion is better than either of the possibilities given above in this question. This is better:
PROC A;
BEGIN
int itemp := atm.ncr.txn_stat; ! my changes !
atm.ncr.txn_stat := expect_tran_l;
case atm.ncr.txn_resp_cde of
begin
shutdown_atm_rc ->
begin
.....
end;
tran_cancel_shutdown_atm_rc ->
begin
if atm_is_faulted then
begin
atm.ncr.txn_stat := itemp;
call send_faulty_screen;
return;
end;
..........
end;
....................
end;
END;
For most programs, the most important thing is to organize the program so that it is very easy to understand what the code does when you come back to look at the code months or years later. There are some programs where the organization that is easiest to understand is not the best choice because it performs much slower than a different, harder to understand organization performs. However, those cases are rare. Learning how to organize a program so it is easy to understand is a large part of what you must learn to become a good programmer. One of the principles to follow is to make procedures flow from the top to the bottom with no returns in the middle. Another principle to follow is to reduce the number of possible paths of control flow through a procedure. In this procedure, eliminating the "if" at the beginning of the procedure reduces the number of possible paths through the code, which usually makes it easier to understand. These are not rules that you can never
violate. As with any art, you should first learn the rules, then learn when it is justified to violate the rules.
Okay, one more thing. I said in my previous post that we probably did not need to discuss the details of the atm_is_faulted DEFINE. However, since you included the details in your post, I see something about it that does not seem to be correct, so let me mention that.
You showed it as:
DEFINE atm_is_faulted = BNA_FAULTY and CASH_HANDLER_FAULTY and CARD_RDR_FAULTY #;
I assume each of BNA_FAULTY, CASH_HANDLER_FAULTY, and CARD_RDR_FAULTY returns true when there is a problem with the aspect it is testing. I also assume that atm_is_faulted should be true when any problem exists. However, the way you have written the DEFINE, it will only be true when ALL of the conditions are true, so I am pretty sure that is not how it should be written. I think it should be:
DEFINE atm_is_faulted = BNA_FAULTY or CASH_HANDLER_FAULTY or CARD_RDR_FAULTY #;
If I am wrong and atm_is_faulted should be true only when all three errors have occurred, then I am wrong and you should ignore this part of my post.
If BNA_FAULTY, CASH_HANDLER_FAULTY, and CARD_RDR_FAULTY return true to indicate that there is NOT a problem with the aspect they are testing, then maybe the DEFINE should be:
DEFINE atm_is_faulted = not (BNA_FAULTY and CASH_HANDLER_FAULTY and CARD_RDR_FAULTY) #;
I think it is unlikely that this form of the DEFINE is the correct one, but I mention it just in case the return values from those three procs are in the opposite sense than their names imply to me.