-scopedbuffers

Posted by agent_008_nl on 07-Mar-2011 08:34

Hi,

The recent discussion about ALL-BLOCKS ON ERROR UNDO, THROW and -undothrow reminded me of another parameter that could spare (some of) us typing and errors caused by forgetting to type. A sessionsetting for bufferscopes. If I want a bufferscope to be on my internal procedure/function/whatever (my personal default), I have to define buffers in them.

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

All Replies

Posted by Thomas Mercer-Hursh on 07-Mar-2011 10:57

Seems to me that scoping requirements vary and that the only clear way to indicate desired scope is to include the buffer definition.  Can you imagine the debugging fun if one ran with such a parameter in production but forgot it in testing or vice versa?

Posted by Admin on 07-Mar-2011 13:19

dislike.

Posted by Admin on 07-Mar-2011 18:02

If I want a bufferscope to be on my internal procedure/function/whatever (my personal default), I have to define buffers in them.

And I personally think it's good that way. There are enough cases where you'd like to have a large buffer scoping - like with variables. A startup parameter would be very global and there is no way to override it in a single location. This is where your request it's different from the UNDO, THROW stuff. The strenght of the ABL has always been backwards compatibility of code. And such a parameter would certainly break that.

I think startup parameters to change the compiler behaviour aren't a good way anyhow. For the UNDO, THROW stuff I'd certainly prefer the statement and probably never use the startup parameter. Also, don't you think we have enough startup parameters already? Missing one would have a big impact on the way the program operates. And how would we add tracability to that?

Posted by agent_008_nl on 08-Mar-2011 02:28

Thomas,

On the scoping requirements later (reply to Mike). The debuggingfun is simple to prevent, just check session:parameters at starup of your test.

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Admin on 08-Mar-2011 02:54

But when it's a compile time session startup parameter, how would you reliable know that you've had the right setting during compile time, ages later, when you are running the code?

Posted by agent_008_nl on 08-Mar-2011 03:16

Mike,

Since a year or 4-5 I have the habit to scope almost all buffers locally - like with variables. The problems with variable scopes that are bigger than a method/function/etc. are widely recognized and documented (even the use of local variables is problematized by f.e. Martin Fowler, see his clarifications on "Remove Temp with Query"),  We should want the strong cohesion and loose coupling of the parts in our programs, wouldn't we. The problems with 'global' bufferscopes are maybe less recognized and documented, but we can find at least some dicussions on the peg about them. I will paste two interesting mails from Sebastien Lacroix below my sig.

  'Overriding' a locally scoped buffer should be possible, by using a global bufferdefinition (using a different namingconvention than for the locally scoped ones).  For backward compatibility in existing applications more local language constructs like the named proposals for undo, throw are required of course. The use of the parameter could be a good choice for a new application.  We have quite a couple of parameters already, adding one would not be that bad. On the tracability see my answer to Thomas.

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

http://www.peg.com/forums/abhack/200703/msg00040.html:

Usage of Private buffers [Re: Betr.: RE: abhack define buffer]
From: Sebastien Lacroix
Date: 13 Mar 2007

--------------------------------------------------------------------------------

Hi Jan,


So you've found the solution is to define the following alias for your
needs:
dvb DEFINE BUFFER buf%\wBuffer FOR %\c.

That being said, I take the opportunity to mention one of my favorite
practice: to use local record buffers to master their scope, however
I define them with the same name as the table name, hence the simple
'dbf' alias you can find in the standard customTabCompletion.txt file:
dbf DEFINE BUFFER %\wBuffer FOR %\c.
to end up with something like:
DEFINE BUFFER customer FOR customer.

I found this out rather recently (a bit more than one year ago only)

What are the advantages?
1) It is no longer possible to make the mistake of typing 'IF AVAIL
customer' instead of 'IF AVAIL bufcustomer' or 'bcustomer', which can
compile fine and lead to very nasty bugs.  Indeed, I have hit this kind
of bug in the past, due to quicky copy/paste made by others.  Such an
issue can take days with the debugger to investigate...
I even made a special tool in the past to scan directories of source
code to detect the suspicious usage of default buffers when additional
buffers had been defined in the same .p's or .w's.  In one application,
I could find 17 other outstanding nasty cases that had not been
discovered yet...  So I can bet cases of bottle of whiskey that there
are many outstanding old bugs everywhere due to that.


2) shorter and smarter


By using only private local buffers for everything (including
temp-tables) in every Internal Procedure/UDF, or passing these buffers
as BUFFER PARAMETER's to other internal procedure or UDF, I never need
to find in what IP a buffer was fetched to investigate a piece of code.

Sure, I will carry on doing the same in OO Classes.


There was an interesting thread on the peg main list a few weeks ago
about this topic.  Obviously, a few of us have foudn out this nice trick
  I fear that a few old players said they would not want to adopt this
practice.  They obviously  do not like to change their habits (BTW they
have probably not even tried abhack...).  I hope I will never have to
debug there code


Good evening.

cheers

Sebastien L.


Jan Keirse a �crit :
>  "someone very helpfull" wrote on 13/03/2007 12:45:20:
>
>> I don't know if this is what you are meaning or not, but did you just
>> want something added to the customTabCompletion Text file.
>>
>> If so add Buf* DEFINE BUFFER buf%\c FOR %\c.
>>
>> To that is that's not what you meant sorry.
>
> It's not what I meant but it made me find this:
>
> dvb DEFINE BUFFER buf%\wBuffer FOR %\c.
>
> I was trying the following:
>
> dvb DEFINE BUFFER buf%\wBuffer FOR %\wBuffer.
>
> which does not work, but de dbf directive showed me how to do what I want!
>
>> -----Original Message-----
>> From:  [mailto:] On Behalf Of Jan
>> Keirse
>> Sent: Tuesday, March 13, 2007 6:21 AM
>> To:
>> Subject: abhack define buffer
>>
>>
>> Hello,
>>
>> I've tried to solve it with the new buffer reference in the custom
>> completion file but it doesn't really work as desired, so here's a
>> request:
>>
>> Would it be possible to make a dvb abbreviation which results in the
>> following:
>> DEFINE BUFFER buf FOR
>> fill
>> in table name here>.
>>
>> It would be desirable to make the buf prefix configurable (other
>> company's
>> might use b as prefix, or no prefix at all (in which case they can
>> already
>> do this)).
>>
>
>
> **** DISCLAIMER ****
> http://www.tvh.be/newen/pages/emaildisclaimer.html"> http://www.tvh.be/newen/pages/emaildisclaimer.html
>
> "This message is delivered to all addressees subject to the conditions set forth in the attached disclaimer, which is an integral part of this message."
>
>
>


--
S�bastien Lacroix

===============================================================
Author of the following guys on http://www.psdn.com:
a) ABHack, free best ever made A4GBL hack to make your dreams come true
in the AppBuilder
http://www.psdn.com/library/entry.jspa?externalID=1886&categoryID=41

b) pure4gltv.w, best ever ADM2 Smart Object (treeview in pure 4GL, you
never dream that far)

l) Enhanced Procedure Object Viewer

--------------------------------------------------------------------------------

url not found:

Re: Buffer Names

From: =?windows-1252?Q?S=E9bastien_Lacroix?=

Date: 27 May 2008


When you do:
FIND FIRST customer.
 
customer is not a table-name but the name of a default buffer for the customer table.  Progress is kind enough to define these default buffers for you.  However, their scope is global to the entire external procedure (.p file)
 
 
When you do:
 
PROCEDURE myProc:
     DEFINE BUFFER customer FOR customer.
     FIND FIRST customer EXCLUSIVE.
 
     [...]
 
END PROCEDURE.
 
   => no need to release your customer at the end of the procedure.  The buffer just goes out of scope.  This solve a lot of problems regarding possible lock leaks or -rereadnolock issue.
Plus, this makes higher quality code.  When you consider an internal procedure, you do not need to know from where it was called to know the context of buffers. 
Note you may also use buffer parameters to 'share' a buffer between two procedures in such a way it is scoped to the caller procedure.
 
HTH
 
Sbastien L.
 
-- 
Sbastien Lacroix
OpenEdge Hacker Consultant on the (battle) fields
 
 
,---------[Author of these guys on http://www.psdn.com]---------------
| a) ABHack Phase Three: free best ever made A4GBL hack to make your
|  dreams come true in the AppBuilder, with OO ABL
|    => proactive autocompletion, analyses and other tweaks
| http://www.psdn.com/library/entry.jspa?externalID=1886&categoryID=1658
|
| b) pure4gltv.w: best ever ADM2 Smart Object (treeview in pure 4GL,
|    you never dream that far)
|
| l) Enhanced Procedure Object Viewer
|---------------------------------------------------------------------
|     It is dangerous to be right when the government is wrong.
|        -- Voltaire
`---------------------------------------------------------------------
 
 
Anita Johnson a crit :
> Hi Greg,
> 
> How do you make a distinction between the table name and the buffer name then?
> How can you tell the difference?  Or do you always just use buffers so you
> always know that it is a buffer?
> 
> Anita
> 
> 
> -----Original Message----- From: Greg Higgins [mailto:] 
> Sent: Tuesday, May 27, 2008 11:49 AM To: Anita Johnson Cc:  Subject:
> Re: Buffer Names
> 
> I do this all the time.
> 
> It localizes the scope of the buffer.
> 
> Some folks feel it is important to change the name of the buffer, I don't.
> 
> Anita Johnson wrote:
>> Hi All,
>> 
>> Can anyone think of a good reason for defining a buffer with the same name as
>> a table name?  We have racked our brains and can't come up with anything.
>> 
>> Thanks.
>> 
>> 
>> Anita Johnson

Posted by agent_008_nl on 08-Mar-2011 03:33

Ah, you are sharp Mike!

I should have answered that it will be possible to check this in the future with the new session attribute COMPILE-PARAMETERS of course! ;-)

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Admin on 08-Mar-2011 05:49

I should have answered that it will be possible to check this in the future with the new session attribute COMPILE-PARAMETERS of course!

Well, it would need to become a new attribute of the RCODE-INFO handle as in a single runtime session there could be R-code from various compile time sessions.

But still I'm not convinced.

Posted by agent_008_nl on 08-Mar-2011 05:57

You have a point again. But first things first, do you recognize the problem I'm searching a solution for now?

Posted by agent_008_nl on 08-Mar-2011 06:37

for some reason the paste of Sebastiens second mail is not completely taken over in this psdn-editor. Retry:

Re: Buffer Names

From: =?windows-1252?Q?S=E9bastien_Lacroix?=

Date: 27 May 2008


When you do:
FIND FIRST customer.
 
customer is not a table-name but the name of a default buffer for the customer table.  
Progress is kind enough to define these default buffers for you.  
However, their scope is global to the entire external procedure (.p file)
 
 
When you do:
 
PROCEDURE myProc:
     DEFINE BUFFER customer FOR customer.
     FIND FIRST customer EXCLUSIVE.
 
     [...]
 
END PROCEDURE.
 
   => no need to release your customer at the end of the procedure.  The buffer just goes out of scope.  
This solve a lot of problems regarding possible lock leaks or -rereadnolock issue.
Plus, this makes higher quality code.  When you consider an internal procedure, you do not need to know 
from where it was called to know the context of buffers. 
Note you may also use buffer parameters to 'share' a buffer between two procedures in such a way it is 
scoped to the caller procedure.

Posted by Admin on 08-Mar-2011 08:59

You have a point again. But first things first, do you recognize the problem I'm searching a solution for now?

Yes, I understand your point. But I don't see that as a real issue that needs fixing... Locally scoped buffers are possible today. When you are seeking a solution to scope all buffers to procedures/methods by default you'll also need a way to override these to globally scope a buffer. What's your suggestion here? (even when Martin Fowler - who has never seen a line of ABL code in his life - makes you suggest that you'll never need them).

And how will you deal with those cases where a buffer should be scoped to a block (DO, REPEAT)?

For all this, there are already solutions in the 4GL - they are clear. Everybody could read the programmers guide (not many developers do so - o.k.) and understand how the program should behave. Regardless of startup parameters.

I think a -defaultnoundo parameter that defaults all variable definitions to no-undo would be higher on the priorities list. But still - I'm absolutely no friend of startup parameters modifying the compilers behavior!

Instead of a startup parameter, you might get me convinced of liking a declarative statement - similar to the ROUTINE-LEVEL ON ERROR UNDO, THROW. That leaves the compile unit selfcontained. Not dependent from too many startup paramters.

Posted by agent_008_nl on 08-Mar-2011 09:53

You have a point again. But first things first, do you recognize the problem I'm searching a solution for now?

> Yes, I understand your point.

Ok, I was (and am still to be honest) in doubt because of this: "There are enough cases where you'd like to have a large buffer scoping - like with variables." For me, when I program, there are not many.

> But I don't see that as a real issue that needs fixing... Locally scoped buffers are possible today.

The issue is comparable to the undo, throw you have to add to every for each etc. If you forget to add it you can get unexpected behaviour. Forget to add bufferdefinitions and you might get a bufferconflict. Besides the issue is that I don't like to have to think of explicitly adding bufferscopes each time as it's my default. I even do not remember using a globally scoped buffer at all the last years (except maybe in a couple of quick and dirty written .w's with a browse where the browse its buffers are globally by default).

> When you are seeking a solution to scope all buffers to procedures/methods by default you'll also need a way to override these to globally scope a buffer. What's your suggestion here?

I suggested a globally defined buffer, with a different naming convention (for example define buffer gCustomer for customer). Or do you mean something else?

>  (even when Martin Fowler - who has never seen a line of ABL code in his life - makes you suggest that you'll never need them).

I did not suggest that. And adopted my habit before ever having read anything by Martin Fowler. Besides writings about architecture by experts that have never read abl-code can be very refreshing. I suspect PSC architects to agree on that. In-breeding is not healthy for the kids.

> And how will you deal with those cases where a buffer should be scoped to a block (DO, REPEAT)?

The old constructs to do that should still work as allways? Not sure, have not used those blockscopes for years.

> For all this, there are already solutions in the 4GL - they are clear.

As clear as structured errorhandling is now, yes. But error-prone and labour-intensive too.

> Everybody could read the programmers guide (not many developers do so - o.k.) and understand how the program should behave. Regardless of startup parameters.

>I think a -defaultnoundo parameter that defaults all variable definitions to no-undo would be higher on the priorities list.

Not on my list. Type DVC in a procedurewindow and you get a definition including the NO-UNDO. Type a query in a function and forget that a local bufferdefinition is generated.

>But still - I'm absolutely no friend of startup parameters modifying the compilers behavior!

I can understand that better now. Just never gave it a deep thought.

> Instead of a startup parameter, you might get me convinced of liking a declarative statement - similar to the ROUTINE-LEVEL ON ERROR UNDO, THROW.

I gave suggestions in that direction.

> That leaves the compile unit selfcontained. Not dependent from too many startup paramters.

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Thomas Mercer-Hursh on 08-Mar-2011 11:12

I'm with Mike in thinking that an explicit statement is the correct way to cause the behavior.  It might be different if the default scope of a buffer were limited from the beginning, but for understandable reasons this is not the case.  Now you are asking that a person change their interpretation when reading the code by no visual clues in the code itself, but by knowledge of what parameters were used to compile it or which will be used to compile it.  In UI terms this is called poor affordance!  Frankly, I dislike the error by block proposal for the same reason when I think about it a bit.  I am a little more forgiving there because structured error handling is new in a way that buffers and IPs are not, and are not so widely used or familiar, but it still has the problem that a person reading the code has to know something that is not visible in the code.  Run time properties don't cut it.  Especially with something this important, I want to see the difference right there in the code I am reading.

Posted by Admin on 08-Mar-2011 11:24

Now you are asking that a person change their interpretation when reading the code by no visual clues in the code itself, but by knowledge of what parameters were used to compile it or which will be used to compile it.  In UI terms this is called poor affordance!  Frankly, I dislike the error by block proposal for the same reason when I think about it a bit.  I am a little more forgiving there because structured error handling is new in a way that buffers and IPs are not, and are not so widely used or familiar,

Exactly. A startup parameter would be useful if you'd wanna try out how the code behaves the one or the other way. Both shouldn't be the way anyone should deal with either error-handling or buffer scoping.

Posted by agent_008_nl on 09-Mar-2011 02:28

As I said I understand Mike's objections against the parameter. What I do not understand is your objection against ALL-BLOCKS ON ERROR UNDO, THROW. If you have this (and of course ALL-BLOCKS BUFFERS-SCOPED) in every sourcefile, you have your visual clue. When programming your queries you don't have to think about adding definitions and changing default on error behavior (what about the on stop by the way). You have less to maintain so less chances to forget something/make errors. Besides your code reads easier, it is less long-winded. Do you want to forget about ROUTINE-LEVEL ON ERROR UNDO, THROW too? Do you program an extra block in each and every routine to change the default behaviour so you "see the difference right there in the code"?  I do not want to be reminded of the obvious each time, my memory is good enough and when I do not trust it I just take a look in the definitions section.

  But maybe I stepped over a discussion that has to come first. I thought that wanting a bufferscope to be as small as possible was as obvious as wanting a variable scope as small as possible for guys like you. But I came in doubt. Am I more strict in my loose-coupling? Do you find Sebastians way of handling bufferscope overdone, and why? Do you really find Fowler not worth reading about variablescope because "he has not read a single line of progress abl"?

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Admin on 09-Mar-2011 02:42

What I do not understand is your objection against ALL-BLOCKS ON ERROR UNDO, THROW. If you have this (and of course ALL-BLOCKS BUFFERS-SCOPED) in every sourcefile, you have your visual clue.

I don't have objections against declarative statements in the files. ALL-BLOCK ON ERROR UNDO, THROW and for heaven's sake also ALL-BLOCKS BUFFERS-SCOPED.

Do you really find Fowler not worth reading about variablescope because "he has not read a single line of progress abl"?

I didn't say, he's not worth reading - but I am very careful with takeing everything he said and wrote as the holy grail.

Posted by agent_008_nl on 09-Mar-2011 03:06

Hehe, getting a bit tired of this discussion eh, Mike? :-)

> I don't have objections against declarative statements in the files. ALL-BLOCK ON ERROR UNDO, THROW and for heaven's sake also ALL-BLOCKS BUFFERS-SCOPED.

Sigh. Thats nice of you! But I reacted on our other friend.

> I didn't say, he's not worth reading - but I am very careful with takeing everything he said and wrote as the holy grail.

I already took your remark as a bit mean rhetorics. A bit like that soccerplayer that told me once that he would kick his opponent in the beginning of the game, just to let him know that he was there. ;-)

And what makes you think that I do not read him careful?

But anyway, I would be interested on your reaction on my suspicion that you are not as strict as for example Sebastien Lacroix in your use of small bufferscopes.

But please take a rest and a cup of coffee and of course I understand it when you think "what the hell". :-)

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Admin on 09-Mar-2011 03:14

...

Posted by Admin on 09-Mar-2011 03:19

But anyway, I would be interested on your reaction on my suspicion that you are not as strict as for example Sebastien Lacroix in your use of small bufferscopes.

I'm typically very concerned about buffer scoping. Especially when updates are involved, I'm frequently using locally scoped buffers or the FOR  phrase in blocks. Don't worry.

With read-only buffers (NO-LOCK), I sometimes purposely use large scopes. Because it is well supported in the language, causes no pain (when done properly), is simple and saves me a lot of typing (your argument turned against you).

But please take a rest and a cup of coffee

Thanks for taking care

Nachricht geändert durch Mike Fechner

Posted by agent_008_nl on 09-Mar-2011 03:33

> I'm typically very concerned about buffer scoping. Especially when updates are involved, I'm frequently using locally scoped buffers or the FOR  phrase in blocks. Don't worry.

> With read-only buffers (NO-LOCK), I sometimes purposely use large scopes. Because it is well supported in the language, causes no pain (when done properly), is simple and saves me a lot of typing (your argument turned against you).

Sometimes... Ok then, you're a brave programmer, you passed the test! :-) And when we have the ALL BLOCKS you will have an even easier life (my invention for you)!

--
Kind regards,

Stefan Houtzager

Houtzager ICT consultancy & development

www.linkedin.com/in/stefanhoutzager

Posted by Admin on 09-Mar-2011 03:39

And when we have the ALL BLOCKS you will have an even easier life (my invention for you)!

 

For those who need it

But I take 50% of the credits for convincing you of a declarative statement rather than a startup parameter. For now, you'll need the ERS back...

Posted by Thomas Mercer-Hursh on 09-Mar-2011 11:27

I don't have any problem about a statement at the top of the program changing the default behavior for that program.   It is not quite as clear and direct as statements on the block, but it is at the top and it is easy to know that one should look whether it is there or not, just as one would check variables, etc., inheritance, and other things which are defined at the top.  My objection is to a parameter which changes the behavior of the compiled code with no trace left in the source.

And, no, I am hardly one to advocate anything other than good separation and loose coupling ... some people even think I am extreme in that regard.

Posted by Thomas Mercer-Hursh on 09-Mar-2011 11:31

Even for read-only blocks I am inclined to tightly scope.  Read it, get what info one needs, and get out of there.

This thread is closed