On 21 Apr 2017, at 02:44, Tim Nevels via 4D_Tech <4d_tech@lists.4d.com> wrote:

> I think we sometimes forget that 4D is not a 3GL programming language like C 
> or C++. 4D is a 4GL language. You don’t get all the feature, benefits and 
> capabilities of a 3GL language in a 4GL language. Remember why we all use 4D 
> instead of using C++. You can get so much more done with 4D in less time and 
> with less programming effort than doing it in C++.

Amen to that ;)  What a thread !

Great discussion.

I feel I must make at least an attempt to convert David’s component-pain to 
pleasure by recontextualising some of the interpretations of the archetype. Of 
course everyone has their personal priorities and preferences so it’s just my 
take, but I have spent 30% of my living existence doing components so I’ll get 
these points of my chest before any more of it passes me by (Life that is).

In general, I find 4D’s component model immensely powerful - still far more 
productive than its 3GL equivalents and there isn’t a lot I would change about 
it. I haven’t read the whole thread but some general points that spring to mind 
are these:

FLAT vs HIERACHICAL METHOD TIERS

In my view, 3GL - 4GL distinction isn’t to do with language, it’s to do with 
complexity.

In a 4GL (well at least in 4D’s implementation) we are always working within a 
unified top language tier which is flat. It’s therefore right that the 
developer should have to disambiguate between method names amongst components 
because the whole point of the component is that it provides a seamless 
extension to the host (flat) method namespace as opposed to some kind of 
hierarchical class-based extension.

DESIGN TIME vs RUNTIME ARCHITECTURAL CONTEXT
As such, it’s not comparable with say a class library or a DLL or other type of 
3GL code module since 4D components are only given an architectural context at 
runtime. This is a huge advantage over traditional coding structures because 
when we design and build components we’re always working in a host context. 
When we’re developing a component, we should not think like a component 
developer, we should think like a host developer because 4D will do the 
architectural contextualisation for us at runtime. If you start to think 
architecture when you’re building components you’ll get very confused because 
there is no architecture at design time. There are of course odd exceptions to 
this but a tiny number and they *are* exceptions, not the rule (See “NASTY 
STUFF” section at the end of this ramble).

NAMESPACES
Remember, 4D owes much of its productivity to implicit referencing, with the 
proverbial elephant in the room being of course the datafile itself. Current 
selections are implicit (within the scope of a process), globals are, methods 
are, form scripts are, form objects are and resources are to name but a few. 
There are no explicitly referencable namespaces anywhere in the language and 
the reason there aren’t any in components is because it would significantly 
disrupt this highly productive paradigm for very little gain and probably a 
measurable productivity loss. As Tim says, it also conflicts with 4D’s identity 
as a 4GL.

CASCADING DEPENDENCIES
Contrary to some of the concerns I’ve seen expressed, you can have components 
call other components in a hierarchy without any problem. In fact you can have 
2 types of coupling in that regard:

1: Tight Coupling
(Where a component references another component’s method explicitly). 
Advantages: compiler is made aware of all calls, compiles as reliably as if all 
methods were host native calls.

2: Loose Coupling
(Where EXECUTE METHOD is used). Advantages: components can be ‘unplugged’ 
without any compiler complaints.

The optimal choice can also depend on short/long term criteria. If your 
component is going to be used all over the place and potentially only 
occasionally, loose coupling can be better. If the component is a permanent 
resident (e.g. a bookkeeping library in an ERP) then I find tight coupling far 
more reliable.

DESKTOP CONFIG: ALL AT THE SAME LEVEL
The fact that a component doesn’t "on board” its dependencies is a GOOD thing, 
not a deficiency IMO. It confines the dependency hierarchy to the logic, not 
where they happen to be located on the desktop and again reflects the 4GL 
paradigm that all components are ultimately an extension of the host top layer. 
You’d end up with a version control nightmare if you had to install the same 
component in 6 different siblings instead of just once at the host level. So 
again, my view is that 4D have thought this through to give us the best of all 
worlds:

 • We have cascading hierarchical dependency supported
 • We have optimal desktop configuration
 • We have a choice of hard or soft coupling

RESOURCES
How 4D handles these is a thing of beauty IMO and is worth including into the 
overall architectural appraisal. When I researched this for my summit 
presentation I actually blew myself away as to the elegance of it because 4D 
manages to deliver much of a 3GL flexible model but with 4GL productivity. 
Consider this: published methods are common, picture resources are not, custom 
constants are common, language resources are not. The result of all this 
architectural weaving is a totally transparent host/component development 
experience because even if you have an extremely complex multi-lingual X-LIFF 
based, custom-constant based, fancy graphic laden structure, you don’t need to 
do one bit of extra work to implement it as a component. Its constants will 
appear in the host - just like a plugin, it’s language resources will be mapped 
appropriately from the method context and form resources will similarly be 
remapped to the component’s resource folder instead of the host’s.

How resources are handled is another hint as to the archetype we should 
appropriately interpret - a 4GL type extension of the “flat” host layer rather 
than a 3GL type subordinate level in a class hierarchy.

ERROR HANDLING
I notice David, you were having issues with this, but I think you may have 
gravitated straight to the exception that’s the most footery aspect of 
components. (If you had been eating a lobster, it would be like picking of one 
of those tiny end-claws and trying to get the meat out of it rather than going 
for the body flesh first :-)).

Ok, components do not have access to each other’s Error variable. So each 
component needs its own independent error handling. (Thats why I said ’think 
like a host, not a component’). HOWEVER, if you want to be fancy about it you 
can write a component utility that does error handling for all memory spaces, 
you just need to provide it with a callback that allows it to grab the “Error” 
value, described below in more detail.

NASTY STUFF
(Only really needed if doing lots of multi-dependent component work, otherwise 
forget)

Actually not so nasty, it’s just that its not as intuitive as everything else 
and is the ONLY place where you need to think like a component developer. The 
single biggest pain with components is knowing which component is calling it. 
Usually you don’t have to know this because the host just passes a pointer and 
then the caller is implicit. But there are occasions where you do, e.g. when a 
callback is needed but there may be multiple components that use us. (“Us” 
being the base component utility that’s doing something useful for subscribing 
components).

Suggested ways to deal with this:
I have 1 base utility component that all other components always are dependent 
on. (It has about 1000 methods or something). Includes Error handling, form 
object utilities, query stuff, you name it. It has a counter which is zeroed at 
startup and increments whenever a dependent component wants a “unique 
identifier” which it uses throughought the session to tell the base component 
“this is me". You can use a more decoupled way to get the identifier, e.g. UUID 
or just the component name itself, doesn’t matter. Then there is an array table 
for callbacks. So, lets say a dependent component that does sales tax 
processing wants to register itself with the utility component. It calls in at 
startup, gets itself an ID, supplies its various callbacks for error handling, 
form parsing, “Get Pointer” proxies, etc and these will form a row in the 
utility component’s callback registry that can be accessed using the registered 
ID.

If no ID is provided, the utility component assumes the subscriber is the host 
(ID=0).

In 3-tier cascading dependency therefore, (HOST -> SALTAX -> UTILS) the 
centralised error handling call from the SALTAX component would look like this:

UTILS_ErrHandler(1;saltaxME)
   SALTAX_DO_AnERRORproneTHING
UTILS_ErrHandler(0;saltaxME)

(saltaxME returns the component identifier ID understood by both the 
subscribing component and the utility component. If SALTAX was in host mode - 
i.e. in development - the call would be exactly the same).

Here, UTILS_ErrHandler does 2 things. UTILS_ErrHandler(1) installs the SALTAX_ 
error handler in the SALTAX_ module. It knows what to call from the subscriber 
callbacks lookup table, so it actually calls SALTAX_ module and tells it to 
install its own error handler. Then, if an error does occur, the SALTAX_ 
handler calls back to the UTILS component to report the error number. The UTILS 
component handles it centrally from then on (using a common form, messaging 
etc). The second call removes the error handler off the ‘stack’ for the 
subscribing component. So here, the utility component is using callbacks to 
manage independent error handlers for ALL memory spaces (subscribing 
components) but handling the response to each error itself.

I know this may slightly horrendous but it’s actually simpler to implement it 
may sound as long as you do it in a “lab environment” - plain pair of vanilla 
structures with hardly any other code in them. It has one huge advantage - you 
only ever need 1 error handler when you’re working with lots of components. 
After that, no need to worry about the context (in which component the error 
occured) so one can go back to being a host developer ;)

WHAT DO WE NEED CALLBACKS FOR ?
In 15 years of component developing, here’s a comprehensive list of the only 
callbacks I’ve ever needed:

  - FORM GET PROPERTIES
 - Get Pointer (for both objects and fields in a (Table;Field) synta)
 - MENU BAR handling
 - GET PICTURE FROM LLIBRARY
 - ON ERR CALL

Hope that helps…and to David A.,  I hope you manage to stick with it long 
enough to write another “Joy of Triggers” episode someday !

-P

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:4d_tech-unsubscr...@lists.4d.com
**********************************************************************

Reply via email to