Embedding Best Practice Step One

An embedding Best Practice that I've evolved for myself over the years is one that puts as little code as possible in the main event loop of the application.

When an event such as a button push or a field alert needs to trigger some hand-written code, the most obvious thing we all do is put the code into the relevant event slot for that control. Fine, if your embed is one or two lines of code. But what if it ends up being 50 or 100 or 200 lines of code?

The outcome of such large, and often structureless embeds is messy, and hard to read or debug once it's in place. One of these embeds in a given procedure is no big deal I guess, but what if you have, say, 20 or 30 such lengthy embeds?

It all gets to be a bit too much to untangle for someone having to work after the fact with your applications.

When that "someone" is you, two or three years down the line, and you have to fix, advance, improve, debug, your own messy, embed code, here follows a Best Practice that I've evolved for myself over the years, that will help to improve the readability and maintainability of your application embeds.

I'm trying to encourage developers -- by setting an example -- in all new demo applications to show that there's a better way to place long embeds. For these applications I've set myself the following objectives:

• To not place any embeds longer than one line of code in all event-related embeds. (You'll see this in, for example, HNDFAVORITER.APP).

• To not use ROUTINES. Routines encourage broad-scope variables and cannot take input parameters or return values as can FUNCTIONS and PROCEDURES.

• To use only local FUNCTIONS and PROCEDURES (METHODS) to implement multi-line embeds.

How does this work then?

It's possible using ABC and CHT templates and classes to add new METHODS to local objects placed there by either an ABC template or a CHT template. Since METHODS can be either FUNCTIONS or PROCEDURES, this is where your long, multi-line embeds should be placed. Done this way, a single embed can be reused by another part of the procedure. And since a FUNCTION-style METHOD can be sent parameters and can return values, the control you have over what any given multi-line embed does, is much improved over in-place embedding and ROUTINE-based embedding.

Step One, then, toward improving your embed code is to simply admit to yourself that there is a better way, and to try something else.


Embedding Best Practice Step Two

Here are two event embeds. The control on the window has been alerted to intercept a mouse click. They both call one of these multi-line methods embedded by hand into the ABC browse object.

Here first, are the two embeds. Next I'll show you how this function BRW3.SetCurrentTopic() was added to this procedure.



Two, one-line embeds in the form of a procedure (method) call with two passed-in parameters, that meets the objective I set above! It also illustrates code reuse and saves on a lot of redundant in-line embed code.

The example code operates on two different variables and two different window controls. I could have written the code twice right inside the respective embed points -- using what I call an in-line embeds. But my window has 12 of these controls on the window. I would have had to re-write similar code 12 different times, if I'd opted for an in-line embed approach. Even using a routine, I can't pass parameters or return values without creating procedure-scope variables, to handle the input and return values.

Now let's see how these two functions were added to the local BRW3 object, an instance of the ABC Browse class.


Embedding Best Practice Step Three

Here you have an image which illustrates the beginning of the function-creating technique.


This is the "Classes" tab of the ABC Browse template. The particular browse instance is BRW3.

I pushed the "New Class Methods" button which lets me insert new METHODS.

You can see a whole list of new methods that I added to hold my various embeds. I did not add these all in one pass. I like to keep the function name as close to what any given function does, so as to make code reading and debugging easier to follow.

Consequenlty, I named and inserted these methods as I advanced the application. Clearly, this app would have been a real mess if I'd placed this many long, multi-line embeds into event slots in-line under the controls themselves.

First of all, I wouldn't have been able to efficiently re-use code, and the code would have cluttered the procedure window's event loop. Now there's no code clutter since each of the multi-line embeds becomes the code portion of a local method. And these methods appear in the lower part of the embeditor window where you don't have to look at them or scroll past them until such time as you want to actually look at the code.


In this third window, I typed in the procedure name (METHOD NAME) and the input parameters. If you don't know how to format METHOD PARAMETERS, shame on you. Its time you got off your duff and learned how to do this. Don't look at me. Look at the Clarion Coding manual. That's Clarion coding 101.

In the next post, I'll take you down inside the embed. (There are two ways to do this --- to get down inside the embed, I mean). There's the hard way and the easy way. You'll see this soon enough in the next couple of steps.


Embedding Best Practice Step Four

In the following image you will see how not to enter the embed points inside this newly added METHOD.

If you enter your code right away while you're already here on this dialog filling in the name, no problem. Knock yourself out, since that doesn't involve any effort other than pushing one of the buttons provided.

The Red arrow points to the area where you'd add some procedure-local data variables.

The Green arrow points the the area where you'd add some procedure-local code.

After creating the METHOD/PROCEDURE, however, I'm in the habit of just leaving this dialog altogether, since I like to enter this newly created workspace (inside the new METHOD) from inside the ABC Code EMBEDITOR.


From inside the ABC EMBEDITOR, I can quickly navigate to all of the embed points available inside the procedure that I'm working on. By creating this new method I've opened up a new embed point into which I will insert my multi-line embed. It provides a single space under an intuitive name into which I can place my code. I can call that code from my event embed points anywhere in the procedure by naming the METHOD -- BRW3.SetCurrentTopic(Param1,Param2) -- and passing in the correct parameters.


If you proceed to the embed point via the code embed button provided above, this is what you'll see next. In this case, I've already done some coding down here as you can see. If this were a fresh method, you would only see a virgin CODE embed area or DATA embed area depending on which of the above buttons you pushed.

It's important to note that in this particular embed I've combined both a HAND EMBED and a TEMPLATE EMBED. I already have a template to store the resulting value in the registry and recall it on opening of the app. No use re-writing the code to do that. I dropped a template down to do that. The other code I needed to write was way too specific to this app to be very useful in template form, so I decide to write that code by hand.


In this last image you see some of the code in the actual HAND EMBED area. It looks like any other embed area in the EMBEDITOR --- which it is. I rarely write my code into embeds like this by drilling down through these template dialogs. I write them after I return from naming the METHOD and re-entering the EMBEDITOR.

In the next step, I'll show you how I got back to this embed spot via the EMBEDITOR without drilling back down through all these dialogs. Can you guess how?


Embedding Best Practice Step Five

This first image -- you already know how to do what it implies.

You need to get into the IDE's EMBEDITOR area for the procedure being worked on. Use the "Source" menu item to get down in there.

If you're doing a lot of embedding, this is how you'll get into here most of the time.


Now what's the big secret about getting to the embed point for the BRW3.SetCurrentTopic() METHOD?

Nothing fancy. Just click the search menu and enter in BRW3.SetCurrentTopic followed by a space. The space is really useful to get you RIGHT to the method definition without stopping along the way at the 12 instances where this method is being called inside the procedure.


Since the actual call attaches an open/close parenthesis at the end of the method name, by adding the space, I'm dropped right at the METHOD definition with is always followed by one or more spaces.


Since as I work on this METHOD code I'm going to be needing the names of things -- variables, in use on the procedure and perhaps the control names on the window -- the code EMBEDITOR's code assist will help me remember the names of these things as I need them. If not, the window definition for this procedure is right at the top of the EMBEDITOR area. Ctrl-Home and I'm there looking at the window code. Then Ctrl-F followed by a click on the FIND button and I'm back where I need to be.

Good developers get intimately familiar with how to navigate a procedure's elements. Since ABC has only 4 major procedure types, its easy enough to get a pretty good understanding of what's where in each of the types.

What are the major ABC procedure types I hear you ask? Sure, the dog ate your homework.

In the next step I'll take you through the code inside our BRW3.SetCurrentTopic() embed. You'll soon see the wisdom of embedding the code this way instead of directly into the event slots (all 12 of them) that we showed you in the very first step of this "Best Practice" article.


Embedding Best Practice Step Six

This is the entire multi-line embed that I would have had to place 12 times if I hadn't written this as a METHOD.

The code is fairly lengthy and there's quite a bit of commentary so that next time I have to deal with this, I'll know what's going on. The actual embed code was too long to show in one image so I've shown it with two consecutive images.



That's a fair bit of code to jam into an event embed. And placing this multiple times (12 times) under 12 controls is obviously amaturish and messy.

I could have used a ROUTINE and made it work. But, look how clean the code is back in our original embed. And since I've used a meaningful procedure name and passed in two specific parameters, (which a routine won't accept) I've got a jumpstart on understanding what's going on here in this event embed. (BELOW)


I chose to use an ABC template object (the browse template) to embed my code into. Why did I do that? Why not a CHT object like HNDDISK (EmbedDiskFunctions) or HNDWINDOW (EmbedWindowFunctions) or HNDMARKERBROWSE? Well by rights I could have done that, but ask yourself this. What's the last template I'm likely to pull off this procedure if I'm making renovations?

Right, I'm not likely to pull the ABC Browse class and its hosting template off this proceudre in favour of one of the other three types of ABC procedure. In effect, I can remove or change some of my templates on this procedure as I see fit, and my code embed points will stay right where they already are, totally untouched by changes to templates, changes to the window controls and so on - no dangling or orphaned embeds.


Gus Creces
The Clarion Handy Tools Page