Hi All,
Can anyone explain what this does please?
The block is...
(for example)
DO FOR order, customer, item TRANSACTION:
/* stuff */
END.
Thanks
Oliver
It's a strong scope block which prevents you from using order, customer, item tables out of it. Well, actually it doesn't make much sense for me, I can't think up any use case in which this block will be really useful.
Thanks!
It does make sense for this particular use I think.
It is in an include file that is used in a lot of places and accesses various settings/parameter tables.
Without the block I suppose it could be altering the currently selected records in the file it is included into.
Thanks again
It is in an include file that is used in a lot of places and accesses various settings/parameter tables
That's a bad practice I'm affraid and I'd do my best to eliminate such an include. But, yes, I agree it might indicate some problems at compile-time.
DO FOR order, customer, item TRANSACTION:
/* stuff */
END.
Like Sergey said it strongly scopes the DO block to the named buffers. If the code is only limited to the snippet above that can certainly create problems at compile time and is not very useful.
However, if the actual code is something like this:
PROCEDURE foo:
DEF BUFFER order FOR order.
DEF BUFFER customer FOR customer.
DEF BUFFER item FOR item.
DO FOR order, customer, item TRANSACTION:
/* stuff */
END.
END PROCEDURE.
This code is *very* useful since it limits the recod scope to the internal procedure and becomes completely independent of any other code in the same compilation unit. Therefore it will not create any problems at compile time.It is a matter of taste if you prefer to write the code like this:
PROCEDURE foo:
DEF BUFFER b-order FOR order.
DEF BUFFER b-customer FOR customer.
DEF BUFFER b-item FOR item.
DO FOR b-order, b-customer, b-item TRANSACTION:
/* stuff */
END.
END PROCEDURE.
I agree with Peter - strong scoping Buffers to blocks is usually very helpful. It makes sure the TRANSACTION block is not accidentally widened because a record has not been released before.
When the DO FOR
is the outermost block in a procedure (internal) it's very similar to
DEFINE BUFFER Customer FOR Customer. /* same name by purpose */
mikefe wrote:
I agree with Peter - strong scoping Buffers to blocks is usually very helpful. It makes sure the TRANSACTION block is not accidentally widened because a record has not been released before.
That is a common misconception. It is not the TRANSACTON scope that matters here (that can always be widened) but the record scope.
When the DO FOR
is the outermost block in a procedure (internal) it's very similar to
DEFINE BUFFER Customer FOR Customer. /* same name by purpose */
That is true. Buffers are already scoped to the internal prcedure, so using DO FOR inside an internal procedure only adds value if there are multiple blocks that must not have bleeding records scopes.
That is a common misconception. It is not the TRANSACTON scope that matters here (that can always be widened) but the record scope.
And that's the purporse of the DO FOR Block.
Peter is pointing you in the right direction here. One is always wanting to limit scope. Bodies of action get encapsulated into procedures or classes so that you know everything that is going to happen about that area of responsibility is in that package. Database transactions get scoped to the smallest possible block, no user input, nothing open ended, in order minimize the length of any locks and to have a small tight block of code where everything that happens to the DB is in that one place. Strong scoping a buffer to a block like this has the same kind of purpose. It is telling you that everything that happens to those buffers happens within that block (there may be another such block in the same program, but no "loose" references or the compiler will complain). Loosely scoped references are a classic way of unintentionally extending the scope of a transaction or lock.
DEFINE BUFFER Customer FOR Customer. /* same name by purpose */
----------
YUK!!! A personal hate of mine. I'd have to beat you with a large stick!
It is a technique that you either love or hate. There is no middle ground on that one.
You may want to beat hime with a big stick but I'll be pinning a medal on him.
That's one of my personal favorites
You may want to beat hime with a big stick but I'll be pinning a
medal on him.
Me too. Easy way to keep readability (no need for any flavour of Eastern European notation) and to ensure buffer scope.
-- peter
YUK!!! A personal hate of mine. I'd have to beat you with a large stick!
Any argument or just dislike?
Heh. I want a medal too, then.
Julian
Heh. I want a medal too, then.
Where do I get mine from?
Its just lazy programming imho. I'd like to think that a buffer falls under the same umbrella as a parameter or variable where naming convensions are concerned particularly where multiple buffers on the same table are referenced in the same block.
Tom's going to have to have a ceremony soon, I guess ..
Its just lazy programming imho.
It's a safety net. And therefor it shouldn't be banned. Basically like a garbage collector in OO ...
It's a safety net
Surely only if you don't define a buffer in the first place?
I'm very much in favor of properly applied laziness and very much
opposed to naming conventions. I prefer to call things what they are
rather than obfuscating them with a bunch of gobbledygook. You would
think that the Western World would have learned its lesson after Roman
Numerals but apparently we are doomed to repeat that particular lesson.
Surely only if you don't define a buffer in the first place?
That explains why you believe you don't have to use it. It does not explain why you'd wanna hurt other developers that do this...
That is exactly the point!
It's a safety net
Surely only if you don't define a buffer in the first place?
If you don't define a buffer explicitly*, it'll be scoped to the outermost block that references it. So if you do a FIND in method/function/procedure A on the default buffer, and reference the same buffer in m/f/p B, it'll point at the same record. You may not want that, and you may spend a lot of time trying to figure out why your code isn't doing what you expect.
Of course, you may want that behaviour, in which case defining a named buffer will cause the buffer to be scoped to method/function/procedure A or B and the other m/f/p won't have access to it. But I personally don't like this because it introduces all sorts of implicit interdependencies; passing a buffer as a parameter (or handle) makes it clear where the m/f/p gets its buffer from in cases where it's "shared". If there's no buffer passed, then I can assume that the intent of the code is to have the buffer scoped to that m/f/p. And clearly, the preceding paragraph has nothing in particular to do with whether the buffer is named "customer" or "bufCustomer" or "roger".
-- peter
explicitly since there's always a buffer
I guess we'll agree to disagree on the "safety net" issue.
Don't get me wrong here. I'm not saying the use of strongly scoped buffers is bad practive. On the contrary, I think its a must. I just don't like to see BUFFER customer FOR customer. However, it seems I am in a minority of 1.
At least two. Explicit buffers are a must, but why obscure the scope of the buffer by giving it a name which means that you can't tell what its scope is?