Alias - Who Was That Masked File?

by Steven Parker

Published 1999-08-24    Printer-friendly version

"File alias" is one of those concepts that is at once extremely difficult and extremely simple. On the one hand, the documentation is quite sparse. Alias is not part of the language, not a Clarion statement (at least in the context of files - there is an ALIAS statement which changes keycodes, but that's not what I'm referring to). The one reference in the online help is to a FileManager method. Little information and, therefore, guidance, is available. On the other, the notion of referring to something by a different name (which after all is what an alias is) is really quite simple: two names, one object.

The behavior of file aliases is entirely a consequence of some Clarion fundamentals: LABEL, RECORD and NAME. When you understand these concepts, it is almost easy to use aliases to solve real world problems.

Why Aliases?

Aliases were introduced to allow multiple relations between files, a feature not supported by the Dictionary Editor.1 Aliases, therefore, provide a second record buffer on a thread for a file. This second buffer also allows looking up recursively within a single file. Aliases are powerful stuff.

Aliases, therefore, are the answer to the question "How can I be in two different places in one file at one time?" Other ways of saying this include: "How can I do a lookup from a file into itself?" "How can I have two different relations between the same two files?" and "How can I relate one record in a file to other records in the same file?"

Recursive lookups and relations are not easily visualized. Perhaps an example or two will clarify the matter.

A fairly clear example is an employee file in which you want to display the employee's supervisor (a job title file displaying the supervisor's title is much the same thing and can serve as the basis for this sort of lookup). Since a supervisor is also an employee (OK, I know that many oughtn't be), there is an interesting and thoroughly unattractive choice: either you can have two files (two copies of the employee or job title file) or you can have one file. Maintaining only one copy of the file means that you have to look up within the current file.

A recursive lookup like this will not work without a major finagle2 and that assumes that you can describe it well enough to create a specification (it's not that easy; try it). Two copies of the same file simply for the purpose of a lookup seems...well, stupid, frankly.

In an inventory module, a bill of materials or kit presents a very similar situation. When displaying a BOM or kit, there will typically be a browse of the items comprising the kit. This is a parent-child relationship. The parent inventory item is the kit but the child items are (or were) also inventory items. Even if the component items are stored in a separate file, they start out in the inventory file. When displaying the components, you need to relate one record in a file to other records in the same file (either directly or indirectly) or keep two copies of the inventory file. When creating the kit, you will need to select items from the inventory file which you are already accessing to insert the kit record. Again, the choices are less than palatable.

My own introduction to aliased files occurred while updating my Go To Lunch batch compiler (available at the CWICWEB download site).

I needed two different browses of the same file on two tabs. On the first tab is a simple browse of the app list. On the second tab, the app list is displayed filtered (actually, range limited). Sounds like pretty standard stuff, right? On the second tab, however, the file is used as a child of another file (Projects) and the second tab shows a list box from the parent file. The app list is filtered on the currently selected parent record (see Figure 1).

Figure 1. The Go To Lunch Batch Compiler showing an  aliased browse ("member" apps).

alias7.gif (6626 bytes)

What is not standard is using a single file standalone and as a child in the same procedure. The standalone instance will set the buffer to the last accessed record. The second instance will always range limit the file on the relating key values. Mashed buffers are a certainty: the file will always end up range limited on the linking field value from the second tab. Even though the first browse appears normal, you will only be able to access the record that is active on the link as currently set on the second tab (opened last, the parent file "touched" the target file last and so gets its way).

Creating An Alias

Before continuing I need to describe how to create a file alias. It's a bit "cart before the horse," but this is the easiest way to present the information.

The Dictionary Editor makes creation of aliases simplicity itself: just press the Add Alias button (see Figure 2).

Figure 2. Creating an alias in the dictionary editor.

alias1.gif (9870 bytes)

This will call the File Alias worksheet, shown in Figure 3.

Figure 3. The File Alias worksheet.

alias2.gif (4461 bytes)

If you are not already using the NAME attribute on the file to be aliased, you will be notified that this is required.

There is no particular reason to use a variable for the NAME, unless you wish to (see NAME() Comes of Age); you can just specify a DOS file name:

Figure 4. Completing the NAME() attribute for the file being aliased.

alias4.gif (8250 bytes)

When you complete all the prompts, your dictionary will look like Figure 5:

Figure 5. The completed dictionary worksheet.

alias5.gif (10062 bytes)

It is extremely important to note that if you do not complete the NAME attribute of the base file, your dictionary will still look like Figure 6. However, when you run the app, a file will be created on disk for the "alias" (if you have file create turned off, you will get an error message). Of course, this defeats the purpose: file aliasing is supposed to work with a single disk file.

NOTE: While the environment will let you complete the worksheet without specifying a NAME, don't.

Finally, given the original purpose of aliases, you will find that the alias inherits the base file's fields and keys but not its relations. You may create any new relations needed, including relations to files already related to the base file. The idea is to use different keys to create new relations.

What Is An Alias?

With the dictionary complete, if you wizard up an application you will notice something quite remarkable. When you examine the application tree, you will see procedures generated for both the base file and its alias. It is as if the Application Generator is treating the alias as an entirely separate file. Think about this; of course it should!

Figure 6. Automatically generated procedures both "files."

alias6.gif (9855 bytes)

If you compile and run the application, you will be able to call both browses and their update forms without incident. Well, of course you should!

NOTE: Do consider checking the Do Not Populate box for any aliases in your dictionary.

If you examine the generated source for the attached sample application, the impression that there are two entirely different files will be further reinforced. Both files are declared separately and without apparent cross-reference in the main source module. There is a FileManager and a RelationManager for each. What you will not find is any obvious connection between the base file and its alias, no reference to the fact that one is the "real" file and one (a sort) of pseudonym. Alias is not a Clarion statement, neither is it an attribute like NAME or CREATE.

If you search all the source files generated (or read the on-line help on the AliasedFile FileManager method), you will find (appNamebc0.clw) a single reference to the alias:

SELF.AliasedFile &= Access:People

in the Hide:Access:PEOPLEAlias.Init method. By referring the alias' FileManager to the base file's FileManager, the ABC classes "know" which is the "real" FileManager (that is, it does not instantiate a FileManager for the alias but uses the base file's FileManager). But you do have to dig to find this.

What is less difficult to miss (though it does not jump out and bite your...nose) is that both file declarations have identical NAME attributes. And this is the key to comprehending what an alias is, how it works and what it does.

Built On The Basics

If you examine the code in the main source module, there are three Clarion key words to consider. Combined, they make file aliases work.

First, you will find a LABEL for each of the files. In the sample application, for example, you will find both PEOPLE and PEOPLEALIAS. Different LABELs allow you to refer to each of them separately (that's what LABELs do).

Next, you will find matching and identical RECORD structures. According to the Language Reference Manual, a RECORD structure is what creates the memory buffer (per thread, if you select the THREAD attribute for the file - see sidebar). And, since there are two RECORD structures, with unique prefixes, there will be two buffers. This is what will allow two different records to be in memory simultaneously.

Finally, the same NAME attribute is used for both file declarations. Therefore, both RECORD structures/buffers refer to the same physical file on disk. And that is what makes an alias work (well, that and the use of the same FileManager3).

To reiterate, declaring a file alias creates both a second LABEL and a second RECORD structure.

"Buffer" is an extremely important concept in Clarion.

A Record buffer is a memory structure which contains values from the currently accessed file record. Think of it as paralleling the file's Record structure.

A Record buffer is created for each file in a procedure when the file is opened. Thus, record (file) buffers are thread specific.

Further, the buffer only contains "fields" for those fields actually referenced in the procedure. In a Form or Process procedure, this is all of the fields. In a browse, it is not. The buffer in a browse contains only those fields populated in the View. Thus, fields in the list box and fields added to the "hot" list contain current data. Any other file field is unreliable.

These are logical entities: like an old-fashioned line number, a LABEL identifies a location in the code and a RECORD is a (dynamic) location memory.

If you run the sample application, you will see that is entirely possible to populate two browses of the same file on a single window without using aliases. It is possible to do this using different keys for each list (select Browse|Browse Both -- Without Alias from the main menu of the example application).

However, no matter what you do, only one record will be in memory. If you run the sample lookup procedure and select a record, you will overwrite the values in the initial record to those of the one selected in the look up. There is no way to look up a supervisor from employee data entry or to select kit items here. Try it, you won't like it.

On the other hand, if you populate a browse from the primary file and a browse from an alias of it, you can have two different records in memory at the same time. Having two records in memory is, of course, not especially noteworthy. What is noteworthy is that both are from the same file, at the same time, on the same thread.

In the sample app, select Browse|Browse Both from the main menu. For each browse box there is a hot field indicating the record in memory for each list. Notice that they are only the same if you intentionally select the same record from each list. Run the matching lookup demo and you will see that it operates just as you expect, just as if there really were two copies of the file.

Using An Alias

An aliased file, of course, can be populated and used in exactly same way as any other file. After all, it has a FileManager (a reference to the FileManager for the base file) and NAMEs a disk file. Thus, the "real" file will be affected by adds, changes and deletes. Even the Wizards and Wizatrons know this.

But that is not what aliases are about.

The special need addressed by the second buffer that an alias provides is when you need to access the same data set twice on a single thread (since buffers are allocated on the thread; again, see the lookup examples in the demo application).

Say, for example, you have an inventory item that is a kit/bill of materials. On its update form you would like a tab with a browse box listing the component items. These component items may well be stored in a child file but their descriptions will most likely be in the inventory file. So, you need to be in the inventory file twice. The first access gets the data for the record being updated and the second gets the descriptions for the component items.

The browse box descriptions for the kit components would be populated from the aliased file (the alias being related to the child as a second parent). The primary record buffer will still contain the data from the inventory record being updated. Neat. No mashed buffers (which is exactly what happens if you use the inventory file directly for both purposes).

Similarly, if you have an employee record in access, a lookup procedure for the supervisor would be created from an alias for the employee file. Again, two different records from the same file in memory simultaneously with no cross talk on the thread.

Caveats

In reviewing an early draft of this article, David Bayliss pointed out that what I discuss here is the "proper" use of file aliases.

Prior to C5B, an alias is always required if you access a file twice on the same thread (not simply in the same procedure) for any reason. He provided the following illustration:

An Employee form has a lookup to Department. The browse on Department also looks up the supervisor name (an employee). There are two accesses to Employee here. They are in different procedures but on the same thread. Because they are on the same thread, they use the same buffer (again, see the sidebar). Prior to C5B, either template set would have problems with this scenario. You could not reuse an existing Department browse.

Since then, intelligence has been added in C5B to try to detect this. Buffers are automatically saved and restored in many cases like this. Specifically, file usage in procedures is monitored (based upon the UseFile method). If a child procedure re-uses a file used by a parent and if the child doesn't explicitly say it wants to overwrite the parent record, Save/Restore file is placed around the child usage. David Bayliss has prepared an article on this subject ("Propitious Memory Corruption") which appears in the next issue.

Summary

If you need to access a file twice on a single thread and those accesses may involve different records, the conventional wisdom is to create and use an alias.

Recursive lookups are the obvious example of needing to access two different records in a single file simultaneously. The other "standard" case is when you need two different relations between the same two files. In these cases, an alias is appropriate and will always work and failing to use one will cause your app to fail.

If you absolutely insist on not using aliases, again see David Bayliss's  article which describes the enhancements to USEFILE.

Download the example application.

Notes

1 The Relational Model also frowns on this practice. But, in the words of Randy Goodhew, the nice thing about the Relational Model is that applications following it rigorously are unusable. Reality often conflicts with theory and, in such cases, the nod tends to go with reality (at least among Topspeeders).

2 If you are not familiar with this term from the pre-PC era, it refers to a programmer's ability to successfully merge geometrically divergent shapes and/or expeditiously scale vertically enhanced edifices (putting square pegs into round holes and leaping tall buildings in a single bound, doof).

3 Of course, you can cut and paste a file declaration, changing the PREFIX, but use the same NAME. You will be able to access the single file from two browses and do so simultaneously. You will be able to update the file from multiple browses simultaneously. You will be able to use one as a lookup file for the other. Ok, so you instantiate a second FileManager. But other than that, what's the big deal?-Clever, eh? Open two browses on a single file created in this way. Change an existing record in one of the browses. Now, highlight the "same" record in the second browse and press the Change button. It isn't updated and, in fact, it won't until you save your edits. So, the big deal is that cleverness can result in lost concurrency checking.


Steve Parker started his professional life as a Philosopher but now tries to imitate a Clarion developer. He has been attempting to subdue Clarion since version 2007 (DOS, that is). He reports that, so far, Clarion is winning. Steve has been writing about Clarion since 1993.

Printer-friendly version

Reader Comments

To add a comment to this article you must log in.

 
 

Search

 

Advanced Search
Topical Index

Related Articles

Subscribe to
ClarionMag

One year: $189

(includes all back issues since '99)

Renewals from $139

Two years: $289

Renewals from $239

More Info

Subscribe Now!

ClarionMag Blog

RSS Feeds

Updates via Email

Enter your Email


Powered by FeedBlitz

Quick Links