Working with 2 include files that use the same variable name

Posted by Admin on 19-Jan-2011 13:52

Hello,

I am on Progress OpenEdge 10.1C SP4. OpenEdge is our backend to our ERP system, Epicor 9.

I am trying to write ABL code that leverages existing objects from our ERP system.

In order to do so, I need to reference 2 include files, which define datasets and temp tables that are used for their respective business objects.

The issue I'm having is that the two include files use the same variable name and I cannot modify either of the include files because it would prevent the business objects from working correctly.

Is there a way to handle duplicate variable names in this scenario?

All Replies

Posted by Admin on 19-Jan-2011 14:06

Is there a way to handle duplicate variable names in this scenario?

Could those include files be used in two different internal procedures, then the answer is yes.

If not, the big question is not just about the conflicting name, it's about conflicting use. Imagine the second used include file, would not define the variable, but reuse the previous one. Would that break the code?

In that case, use something like

&IF DEFINED (i_is_ already_defined) EQ 0 &THEN

DEFINE VARIABLE I AS INTEGER NO-UNDO .

&ENDIF

&GLOBAL-DEFINE i_is_already_defined

This will prevent the compiler issue and should not break any other code using just a single include file.

When you need to prevent a conflicting use of the variables, think about prefixing a variable with an include file parameter.

DEFINE VARIABLE {&prefix}i AS INTEGER NO-UNDO.

Where you use the variable:

ASSIGN {&prefix}i = {&prefix}I + 1.

When you don't pass the include file parameter, nothing will change. When you pass it, it will result in unique variable names.

Posted by Admin on 19-Jan-2011 14:31

Thanks Mike! I appreciate the quick repsonse.

I understand most of your post but I don't really follow the solution (this is my first attempt at writing this kind of code).

It sounds like your saying that I could manage this by leveraging scopes with in procedures.

Right now, the includes are are the top of my code.

It looks like this:

{Bpm/Bpm.i &OBJECT_NAME=Quote }
{core/CallContext/CallContext.i}
{bo/SalesOrder/SalesOrder_ds.i}

procedure CreateOrderAfter:
     define input-output parameter dataset for QuoteDataSet.
     define input-output parameter orderNum as integer.
{&TRY_PRIVATE}

...

It's not obvious but the line {Bpm/Bpm.i &OBJECT_NAME=Quote } pulls in an include file called Quote_ds.i, which is conflicting with the SalesOrder_ds.i

Can I move the line, {bo/SalesOrder/SalesOrder_ds.i}, into another procedure so that it's scope is within this new procedure?

For example:

procedure CreateOrderAfter2:

     {bo/SalesOrder/SalesOrder_ds.i}

...

Would I still have the conflict because the other include is defined "Globally"?

Posted by Admin on 19-Jan-2011 15:21

It sounds like your saying that I could manage this by leveraging scopes with in procedures.

Sorry, I did overlook the fact that you're talking about temp-tables and/or datasets?

They cannot be defined in internal procedures, so drop that comment please.

So it's still up to understanding if you have a conflicting use (vs. just a conflicting definition). If you have a conflicting use, you'd have to go the way of defining the temp-tables and ProDatasets with a preprocessor prefix like demoed for the variable.

Posted by Thomas Mercer-Hursh on 19-Jan-2011 16:13

Before going much farther, you should probably step back and realize that this is not just some accident or awkward problem to work around, but that the underlying issue is that there is a sub-optimum decomposition of the code here.  I know you are probably just trying to get the job done in the quickest possible way with minimal change and effort, but the real issue here is that the problem shouldn't arise in the first place.

Mike is more friendly toward includes generally than I am.  They are the source of quite a few potential problems in ABL coding, some of which relate to difficulty in analysis ... and, of course, difficulty in analysis translates into difficulty in coding because one has trouble knowing what the right thing is to do.  They also present issues in coding itself, such as the one you are experiencing or another famous related example where there are multiple temp-tables in one include, but not all are used and this leads to performance problems.

Myself, I dislike the principle of putting temp-table definitions in includes since the only real reason for doing so is to use the same definition in multiple places and I would much rather have that usage encapsulated into a reusable piece of code.  Encapsulate the functionality associated with a temp-table into a separate piece of code, a compile unit, and you can use that code anywhere you need the functionality without having to spread the TT definition around the universe.  If you ever need to modify the TT or functionality, it is in one place.  You know where it is and, unless the change impacts the calls on the functionality, you don't even need to modify the places where the code is used.

But, if you *HAVE* to use the style of putting TT definitions into include files to be used multiple places, there should absolutely be nothing except the TT definition in the include.  If there are other variables needed in association, fine, put those in another include, but don't mix plain variables and TT definitions in the same include file.  Ever.

So, the best solution here ... assuming that you can't be radical enough to move the functionality of each TT into its own program/object, is to reslice the include files so that the TT definitions are separate and then there are one or more sets of variable definitions.  I am a little suspicious of includes which consist of only variable definitions because it is very easy for them to be used in places where not all of the variables are actually referenced and that muddies analysis.  Besides, in most case very, very little is saved by substituting a few lines of variable definitions for an include and, at the least, it has been made more obscure.  But if you *HAVE* to put varible definitions into includes, make sure that you parition them by use so that they are in minimal functional clumps, so that only what you actually need is included in any one program.  Do that, and you won't ever have the same variable in two different include files because that is an unambiguous clue that the set is not minimal.

Posted by Admin on 19-Jan-2011 16:21

But, if you HAVE to use the style of putting TT definitions into include files to be used multiple places, there should absolutely be nothing except the TT definition in the include. If there are other variables needed in association, fine, put those in another include, but don't mix plain variables and TT definitions in the same include file. Ever.

From the original post:

I am trying to write ABL code that leverages existing objects from our ERP system.

In order to do so, I need to reference 2 include files, which define datasets and temp tables that are used for their respective business objects.

 I would be surprised if changing the interface to the existing ERP code is actually possible.

Posted by Thomas Mercer-Hursh on 19-Jan-2011 16:25

As I said, in the context, it is probably not going to get refactored ... but that doesn't prevent one from recognizing the bad practice that leads to the problem, even if the work around is just to put in explicit definitions, reference the includes in comments, and move forward by brute force.

However, if one has source and especially if the source in question is local rather than part of the vendor's standard release, then it is quite possible to refactor the existing code along the lines I have suggested to avoid additional problems in the future.

Posted by Admin on 19-Jan-2011 19:43

Thanks Mike and Thomas,

The conversation has been very helpful and I'm learning alot.

To answer Mike's question, it looks like the conflict in names is both a use as well as definition problem.

There are multiple temp tables that share the same name, some are identical but at least one is not.

I'm not totally familar with the preprocessing option that you're proposing.

Could you provide a little more detail on how I can (or if I can) handle the duplicate names?

Thanks!

Posted by Thomas Mercer-Hursh on 19-Jan-2011 22:31

If you have two include files which use the same name for different variables or temp-tables, then from an overall perspective you have an even bigger problem.  One should never put something in an include file which has a likely naming conflict with anything outside an include file or in another include file.  Duplicating the identical variable definition in two include files is understandable, although unfortunate and an indicator of a need for a change in decomposition, but duplicating the name, but different definitions is just a mess.

Short answer is to just ignore the include files.  Copy the contents into your program and alter naming and eliminate duplicates as needed to get something to work.  Add comments about where the original is and why you didn't use the include file.  Report the problem to your boss for resolution.  Explain why this is a problem and point to this thread.  No fancy use of preprocessor logic will fix the problem of two include files that use the same name for different things.

Posted by Admin on 20-Jan-2011 01:45

I fully agree with Thomas, that having two temp-tables with the same name but different schema is very dangerous, but I understand your situation.

In the include file, do something like this:

DEFINE TEMP-TABLE {&prefix}test NO-UNDO

    FIELD character1 AS CHARACTER .

CREATE {&prefix}test .

ASSIGN {&prefix}test.field1 = "Hallo".

/* and so on */   

When you include the include file, specifying &prefix is optional, so you can optionally rename the temp-tables to prevent the naming conflict:

{ttdef.i &prefix=abc}

{ttdef.i &prefix=xyz}

{ttdef.i}

An interesting fact is, that temp-tables as parameters are validated by the schema, so the fields, not the table name. So if one procedure uses a name prefix (or suffix if you prefer) and the called .p does not, it will still work!

Posted by Thomas Mercer-Hursh on 20-Jan-2011 11:41

I suppose it is worth noting that there is no solution here which does not involve modifying existing source *except* ignoring at least one of the includes and manually putting in the definitions.  Mike's suggestion does allow you to modify only the includes and not touch the other source where they are used, but you will have to remember to use the prefix in your own new code, which will make it not quite the same as existing code.  What ever you decide to do, make sure you comment it thoroughly so that the next person who comes along can know what you did and why.  I can think of few more compelling cases for comments than a situation like this.  And, if you do take a minimalist approach for the sake of getting the job done quickly, I would write up a description of the problem and the proposed solutions and pass it up the chain of command so that someone is aware of the issue.

This thread is closed