define trigger on entity level | Uniface 9 | Forum

Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

—  Results per page  —








— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters
For a group of consecutive words like 'end of support' use Match phrase

sp_Feed Topic RSS sp_TopicIcon
define trigger on entity level
01 Jun 2018
4:48 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi freaks

Did anyone of you use the define trigger on entity level?
I just did so and got a strange listing (9.7.04)

Trigger <DEFE> from Entity: TABLE.MODEL
[ 1] #define ENTITY_TYPE=XYZ

Trigger <DEFE> from Entity: FIELD.MODEL
[ 1] #define ENTITY_TYPE=XYZ
Trigger <DTLF> from Field: FIELD.TABLE.MODEL

What the … is this defintion for entity FIELD.MODEL?

BTW:
And, this defines are not local to the entity 🙁

 

Background:
We do have different ‘types’ of entities in a component, like visible entities or auxiliary entities.
I looking for a simple way to tell the globale procs (for read or write or …) which kind of entity it is.
For the whole component, this could be done by the DEFINE-trigger and some coding in a general INIT-Operation.

But how to do this for entities?
 a) the DEFE trigger should do what it have to do. And this local to the entity
 b) I need some kind of INIT for the entity (collection)

Any ideas?
BTW: This should not interference the rest of the code, as my colleagues don’t like to change there code or see changed code 🙂

Ingo

01 Jun 2018
5:40 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

So, I got a “solution”

I do a define in DEFE: #define ENTITY_TYPE=XYZ
In ECOP I did already have a operation returning some useful information about the entity/collection.
In this operation do some “magic” with precompiler statements to set the return parameter.
After this I do a #undefine ENTITY_TYPE to be sure, that no other ECOP catch this definition.

Now I can call the ECOP-operation from every globale proc to check, on which entity type I’m working.
To avoid a call to this operation, I could store the information at first call in $entityproperties, but this will sometimes crash …

Let’s hope, that the sequence of compiling will not change

@UnifAce
A little more Reflection would be nice 🙂

 

Ingo

05 Jun 2018
7:29 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

“Nice” inheritance Confused

In each define-trigger for groups on model level (TPLACTUAL.UCGROUP) write an #include into the trigger
 #include STD_DEFE

Create a componente and put some #defines before the include into the define trigger (TPLACTUAL.UXGROUP)
  #define DOSOMETHING
  #include STD_DEFE

How often will STD_DEFE excuted on compilation?
Not not once but twice

If the include start with an guard like:
 #ifundefined STD_DEFE_GUARD
  #define STD_DEFE_GUARD
  #ifdefined DOSOMETHING
    #info somethingtodo
  #endif
#endif
what is the result?
Yes, you guess it.
#info will never reached

Why?
On first round, UnifACe includes the modell define-trigger: Guard is therefore armed
Second step, the component define-trigger is “executed”. But as the guard is armed ….

So one need a two step guard to get this one to run.
And as in documentation there is no hint about inheritance and the sequence of resolving the triggers, I do not trust UnifAce that model is always for component.
As an consequence, the include will be executed two times.

@UnifAce:
a) Is there any way to stop UnifAce from resolving two times?
b) is there and precompiler constant to check, if I am on model or component level?

Ingo

06 Jun 2018
11:20 am
Avatar
gianni
Member
Forum Posts: 301
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Ingo

I hope you talk to someone in between your 3 posts…
while reading them from far away, it seems you are talking to yourself!
🙂 🙂 🙂

Just smile…you’re on candid camera!

Gianni

06 Jun 2018
11:34 am
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

gianni said
Ingo

I hope you talk to someone in between your 3 posts…
while reading them from far away, it seems you are talking to yourself!
🙂 🙂 🙂

Just smile…you’re on candid camera!

Gianni  

Hi Gianni

All my colleagues are on vacation Cool
But maybe out there, some will read my posts.
Increase: UnifAce will read it
And -fingers crossed – UnifAce will answer or fix the problem Wink

Ingo

06 Jun 2018
2:12 pm
Avatar
Gerton Leijdekker
Amsterdam
Member
Forum Posts: 51
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Ingo,

this a bit tricky to explain, but I will give it a try.

In Uniface 9, in context of inheritance, we need to make a distinction between two types of triggers:

1. triggers that perform container-base inheritance: meaning the complete content of the modeled-level trigger is overwritten by the local/component-level trigger if there is any data in that local/component-level trigger. Triggers of this type are all Standard Triggers (read, write, etc.) and Local Proc Modules (basically all OLD triggers – pre Uniface 7)

2. triggers that perform inheritance per Proc Module (trigger/entry/operation): both the content of the modeled-level and the local-level trigger are concatenated and in case of duplicate definitions, the last one wins. Triggers of this type are the Defines, Extended Triggers, and Operations triggers (all new triggers, introduced in Uniface 7).

The problem is in the UDE. The UDE shows a kind of code pre-view and does this as if the trigger is of type 1, which is fine for all triggers that are of type 1, but very misleading for triggers of type 2 where it sim ply gives the wrong impression.

An example: You have some code in the Defines trigger at modeled-level. In the Component Editor, you see that inherited code because there is no local code in the trigger (yet). This is fine as and very useful as long as you don’t add any local code. But what happens if you start changing the code that you see (but not is)? A copy of that code is made to local-level and your changes are applied. Now, for the type-1 triggers this is fine, because the modeled code is no longer inherited, but for the type 2 triggers this is not fine, because (as stated above) you now have a some modeled code AND some local code. It does not have to be a problem, but could be, depending on what you do.

(This is an old bug (as of Uniface 7), and before you ask, we tried to solve it once and simply received too much complains about the fix that we decided to roll the fix backCry)

So back to your problem. What you see is correct: your #include is process twice because it is actually defined twice: at modeled-level AND at component/local level.
To avoid this situation is not to change the inherited code that you see in the Defines trigger at component level, but to first complete clear that trigger and ONLY put your local code in there. The inherited code WILL get inherited at compile time, even if you do not see it in the UDE.

So for type-2 triggers, why do we compile the modeled code also? That has to do with the inheritance type, we want to inherit per Proc module declaration, but to get the declarations, we need to compile first. Module declaration might get included (#include), get generated (#for), or conditionally declared (#if), or even undeclared (#undeclare). So we MUST compile first, and then resolve inheritance.

I hope this explains it and allows you to figure out what to do. If not, reply some more.

Regards,

Gerton
(Software Architect Uniface Lab)

06 Jun 2018
2:37 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Gerton

ThanX for the long answer

All what you did say is what I thought too about the logic behind the curtain 🙂
The “problem” here is, that I want to define some precompiler constants in DEFE-trigger on component level AND want to react to this by the an include in this trigger.
E.g depending on the kind of an entity (declared by #define CLL_TYP=xyz in DEFE) , some other constants should be definend in the include of DEFE and in ECOP-trigger proccode should be manipulated.

So it is essential, that DEFE be will resolved in a “proper way” before ECOP.
And as lessens learnded in C/C++, an include should be guarded against include twice

But with DEFE in UnifAce, the guard will turn to a devil, as the #defines in DEFE will not proper checked 🙂

So the questions are
a) Will the sequence for one entity always  DEFE(model)->DEFE(component)->ECOP ?
b) Is there any way to check, if I am on model or component level?
c) Is there a way to check, if or if not a DEFE(component) will follow?

Explanation
Currently I did guard the include by two guard-statements.
A third time, this include will “fail”
But I have to do consider both time the included, as I don’t know wether the second -component DEFE- will be resolved or not.
The precompiler code in question is now stable againts this double resolve, but the listing looks awful 🙂

TIA
Ingo

06 Jun 2018
4:23 pm
Avatar
Knut
Member
Forum Posts: 211
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Ingo,

I might have misunderstood the issue, but;
I’ve had #include inside of another #include – with compile time constants wrapped in and around
the content of the #include – thus I only ended up with it being included once..

It gets kinda messy, but it solved the issue you described (I believe).

Knut

06 Jun 2018
5:16 pm
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Ingo, Gerton and Knut,

so all we have to do is to put our relevant local modifications in front of the modeled one for the compile.

So each relevant modeled trigger starts with:

#include locals_<$entname>_<$triggerabbr>

And in this include proc, we can add our local modifications as

#if <$componentname> = MYCPT1
#define DOSOMETHING
#endif

Perhaps you can give it a try in a real-world context,
Uli

06 Jun 2018
5:37 pm
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

… and to get the correct modified code for procs without a guard, the local trigger will have a trailing (or only)

#include locals_<$entname>_<$triggerabbr>

This way all the not guarded entries are compiled again after all the modeled ones,
so the modifications should be executed.

06 Jun 2018
7:01 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi all

All I want do do is to have a default behavior and sometime a special one 🙂

So I wrote for some (1) triggers a standard include file named STD_<abbr> (2) and put them in the triggers as default code
1) This are e.g. DEFN,DEFN, OPER,ECOP,EOOP,…
2) <abbr> is here a literal not the precompiler $triggerabbr

For DEFx, a developer can include own DEFINEs in front of the #include, for other triggers, the proc code gets in after the #include
So every component got a lot of useful extra operations and other “helpers”

But sometimes, you have to change the default behavior a little bit.
So define a flag #DEFINE DO_SOMETHING in DEFN and the component does something other
Define e.g #DEFINE CLL_TYP=SUI in DEFE and the triggers know how to handle SelectUserInterface-entities

The goal is, to minimize the ToDo’s for developers but use the precompiler to “solve” most of the issues.
So it’s important, that the sequence of resolving triggers is stable and defines are resolved before other triggers.
And as there are includes like STD_CONSTANTS I don’t want to include them over and over. Only this first time I need them.
On other hand, if there is a change to make at global level, it should be necessary to recompile all forms. So global things to execute are in global procs.
As you know, it’s not easy to find a balance between precompiler and global procs, but I believe, I got a good one

BTW:  Our application is over 20 years old, so it’s not so easy as if you can do all this from the scratch 🙂

Ingo

06 Jun 2018
7:30 pm
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Gerton,

as I understand, the whole process you explained runs with the motto “the last definition overwrites the previous one”.

So you compile the modeled ones before the local ones, but precompiler guards do not follow this rule.
And if one wants a variation to win you have to code it AFTER the modeled one,
he has to touch the entities code, what means these variations are scattered in a lot of different places.

 

Let’s assume we change the motto to “the first definition blocks the following ones”:

Local variation is compiled BEFORE the modeled one so precompiler guards are working as expected.
AND to make coders and readers life easier:
one can even code all variations of entity modeled procs in the Local Proc Module of the component without any protection.

Wouldn’t this be an option which respects type 1 and type 2 and the #define logics as well?

06 Jun 2018
7:41 pm
Avatar
Gerton Leijdekker
Amsterdam
Member
Forum Posts: 51
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Okay, it is getting quirky. I did a small test that shows how the pre-compiler runs through the code and handles #defines:

I created a modeled entity and a component that uses that modeled entity, with the following code:

  Modeled Entity Component Entity
Defines (DEFE)
#define myColor = WHITE
#warning ModeledEntity/DEFE: ‹myColor›
#warning ComponentEntity/DEFE: ‹myColor›
Collection Operations (ECOP)
#warning ModeledEntity/ECOP(1): ‹myColor›
#define myColor = YELLOW
#warning ModeledEntity/ECOP(2): ‹myColor›
#warning ComponentEntity/ECOP: ‹myColor›

When compiling I get the following result:

(2\DEFE) warning: 1000 – ModeledEntity/DEFE: WHITE
(2\DEFE) warning: 1000 – ComponentEntity/DEFE: WHITE
(2\ECOP) warning: 1000 – ModeledEntity/ECOP(1): WHITE
(2\ECOP) warning: 1000 – ModeledEntity/ECOP(2): YELLOW
(2\ECOP) warning: 1000 – ComponentEntity/ECOP: WHITE

What we see here is that:

– all 4 triggers get pre-compiled, as expected for a type 2 trigger (see my explanation above), because we get all 5 warnings (try doing the same with a type-1 trigger like read)

– e.g. the order of compilation is: ModeledEntity/DEFE –> ComponentEntity/DEFE -> ModeledEntity/ECOP –> ComponentEntity/ECOP.
So, compilation is handled per trigger includes trigger inheritance, before doing the next trigger.

– because of the scope of #defines in DEFE, all #defines defined in DEFE are available in other triggers as well

– because of the scope of #defines in triggers other then DEFE, any #defines are ONLY available in that trigger. So the redefinition of #define in the ModeledEntity/ECOP to YELLOW is only available in the modeled ECOP and does NOT get inherited!

So, what you’re trying to do, being a #define in a modeled level trigger other then DEFE will NOT get inherited. If used to check a condition, that same condition will result in something else at component level.

06 Jun 2018
8:41 pm
Avatar
istiller
Member
Forum Posts: 251
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Gerton

First: Is your table correct?
It looks like, you put the #define myColor = YELLOW into the ECOP of component level instead of DEFE of component level.

And scond, I  don’t wrote the #warnig direct into ECOP but by include

  Modeled Entity Component Entity
Defines (DEFE)
 
; #define myColor = here your color
#include STD_DEFE
#define myColor = YELLOW
#include STD_DEFE
Collection Operations (ECOP)
#inlude STD_ECOP
./.

Where

– STD_DEFE
#warning DEFE: ‹myColor›

– STD_ECOP
#warning ECOP: ‹myColor›

So I got three warnings *)
#warning DEFE: WHITE
#warning DEFE: YELLOW
#warning ECOP: YELLOW

Ingo

*) could not give you the exact warnings as I at this very moment in a pub Laugh

07 Jun 2018
7:40 am
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

Hi Gerton,

looks like I was not precise in my post, as I used the term “#define” not as a simple define, but as a shortcut for Ingos “guarded” example:

The local variation is:

#define DOSOMETHING
; the local one
#ifundefined STD_DEFE_GUARD
#define STD_DEFE_GUARD
#warning guarded is active
#ifdefined DOSOMETHING
#warning somethingtodo locally
#endif
#endif

The modeled code in DEFE reads:

#ifundefined STD_DEFE_GUARD
#define STD_DEFE_GUARD
#warning guarded is active
#ifdefined DOSOMETHING
#warning somethingtodo
#endif
#endif

The compile returns:

Phase 7: Procs compilation
(2\DEFE) #warning guarded is active
(2\DEFE) warning: 1000 – guarded is active

And the listing says:

Trigger <DEFE> from Entity: A_TEST1.A_TEST

[ 1] #ifundefined STD_DEFE_GUARD
[ 2] #define STD_DEFE_GUARD
[ 3] #warning guarded is active
(2\DEFE) warning: 1000 – guarded is active
[ 4] #ifdefined DOSOMETHING
[ 5] ;#warning somethingtodo
[ 6] #endif
[ 7] #endif
[ 8] #define DOSOMETHING
[ 9] ; the local one
[ 10] #ifundefined STD_DEFE_GUARD
[ 11] ;#define STD_DEFE_GUARD
[ 12] ;#warning guarded is active
[ 13] ;#ifdefined DOSOMETHING
[ 14] ;#warning somethingtodo locally
[ 15] ;#endif
[ 16] #endif

 

Because the modeled code already sets the STD_DEFE_GUARD,
the local #define DOSOMETHING will never result in a warning.

07 Jun 2018
8:06 am
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

And I used the MNUS trigger to simulate the alternative motto where the first definition wins:

; Let’s assume we change the motto to “the first definition blocks the following ones”:
; Local variation is compiled BEFORE the modeled one so precompiler guards are working as expected.

#define DOSOMETHING
; the local one
#ifundefined STD_DEFE_GUARD
#define STD_DEFE_GUARD
#warning guarded is active
#ifdefined DOSOMETHING
#warning somethingtodo locally
#endif
#endif

; the simulated modeled one
#ifundefined STD_DEFE_GUARD
#define STD_DEFE_GUARD
#warning guarded is active
#ifdefined DOSOMETHING
#warning somethingtodo
#endif
#endif

 

Compile returned:

(MNUS) #warning guarded is active
(MNUS) warning: 1000 – guarded is active
(MNUS) #warning somethingtodo locally
(MNUS) warning: 1000 – somethingtodo locally

 

And the listing reads:

Trigger <MNUS> from Form: A_TEST1

[ 1] ; Let’s assume we change the motto to “the first definition blocks the following ones”:
[ 2] ; Local variation is compiled BEFORE the modeled one so precompiler guards are working as expected.
[ 4] #define DOSOMETHING
[ 5] ; the local one
[ 6] #ifundefined STD_DEFE_GUARD
[ 7] #define STD_DEFE_GUARD
[ 8] #warning guarded is active
(MNUS) warning: 1000 – guarded is active
[ 9] #ifdefined DOSOMETHING
[ 10] #warning somethingtodo locally
(MNUS) warning: 1000 – somethingtodo locally
[ 11] #endif
[ 12] #endif
[ 14] ; the simulated modeled one
[ 15] #ifundefined STD_DEFE_GUARD
[ 16] ;#define STD_DEFE_GUARD
[ 17] ;#warning guarded is active
[ 18] ;#ifdefined DOSOMETHING
[ 19] ;#warning somethingtodo
[ 20] ;#endif
[ 21] #endif

07 Jun 2018
8:39 am
Avatar
ulrich-merkel
Frankfurt/Germany
Member
Forum Posts: 1782
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

OK, back to our reality and a little “cave canes”:

It looks like the guard to stop multiple executions on an include proc cause problems;
but these multiple compiles will not do any harm as local variations will overlay the modeled code.

As we see without the guard, compiling modeled code in front of the code with the local variations
will end up that the local variation will be processed at runtime (which is the expected way).

So all it takes to clear Ingos problem from post #3 is to deactivate
the 3 lines defining guard in the (centralised) include procs.

;#ifundefined STD_DEFE_GUARD
;#define STD_DEFE_GUARD
#ifdefined DOSOMETHING
#info somethingtodo
#endif
;#endif

Greetings from Frankfurt/Germany,
Uli

P.S. I don’t like the idea of a “naked” local code as the traditional way shows me all the relevant code at once.
It’s a bit irritating in U10 that first one has to copy a proc out of the model window to start a local variation.

07 Jun 2018
9:22 am
Avatar
Gerton Leijdekker
Amsterdam
Member
Forum Posts: 51
Member Since:
01 Oct 2012
sp_UserOfflineSmall Offline

To Ingo: me example is as I intended. I wanted to demonstrate that the #define = YELLOW at MeldedEntity/ECOP does not inherit into component.

To Uli (at some point): You are right, it does not harm the end-result of compiled modules, but still you could also have ‘business’ logic in defines and you need to keep a good eye on it.

To Uli (last point about U10): You are right, at some point we still want to add an option to copy the modeled code into the component, so it can be sued as a starting point.

Thanks guys, interesting discussions.

07 Jun 2018
2:20 pm
Avatar
Lauterbach
Member
Forum Posts: 30
Member Since:
06 Dec 2012
sp_UserOfflineSmall Offline
Forum Timezone: Europe/Amsterdam

Most Users Ever Online: 131

Currently Online:
17 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

ulrich-merkel: 1782

Iain Sharp: 653

Theo Neeskens: 353

gianni: 301

rogerw: 260

istiller: 251

Knut: 211

lalitpct: 197

Arjen van Vliet: 175

sochaz: 173

Member Stats:

Guest Posters: 3

Members: 8718

Moderators: 0

Admins: 8

Forum Stats:

Groups: 1

Forums: 62

Topics: 2192

Posts: 9481

Newest Members:

VikaDit, Refomibon, NapsdqaLews, BssaeqiLews, vasin159, NYAlex, Demodom, DorrisSek, HousepfReviews2, gahaddence

Administrators: admin: 23, Adrian Gosbell: 317, diseli: 958, Bob Maier: 3, Nico Peereboom: 77, Michael Rabone: 4, richiet: 406, JanCees: 28