Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

One of my favorite and least favorite classes in DCL is When I need to work with text files I usually turn to DCL_System_IO_AsciiFile, an updated version of Konrad Byers' AnyAsciiFileClass originally published in Clarion Magazine.  . ItBut there's one of my favorites because it's so useful; it's one of my least favorites because there's a very inelegant bit of code needed to start using it. 

Shortly after I began using AnyAsciiFileClass I ran into a situation where I needed multiple instances of the class; I needed 

One of the changes I made to the class was to add support for multiple instances. Originally, AnyAsciiFileClass contained a single file definition declared in the class's CLW file:

Code Block
AnyAsciiFile            FILE,DRIVER('ASCII'),CREATE,NAME(AnyAsciiFileName),PRE(AsciiFile)
                          RECORD
TextLine                    STRING(ANYASCII_IO_SIZE)
                          END
                        END

The problem is that data declared in a class module is shared by all instances of the classthing about the class that drives me up the wall: it needs some clunky initialization code. 

It wasn't always that way - the original class was much more intuitive.Things started to get ugly when I needed to work with two text files at the same time.

I tried declaring two instances of the class, but the code didn't work. That's because the class contained only one ASCII file declaration, and no matter how many instances of the class I created there was still just one ASCII file. Multiple classes using the same file declaration for operations on multiple text files is a recipe for disaster

By way of example, here is a simple class I've called DemoClass. This is the .INC file:

...

You can see that the CLW file contains a declaration of a LONG variable, and the declared outside the class but inside the class's source module. The one method in the class returns the address of this variable. 

Now here's a small program to prove that SomeClassModuleData is the same in all instances of DemoClass:

Code Block

										PROGRAM
										MAP
										END

	include('DemoClass.inc'),once
InstanceA                               DemoClass
InstanceB                               DemoClass
	CODE
	if InstanceA.GetClassModuleDataAddress() = InstanceB.GetClassModuleDataAddress()
		message('Class module data address is the same for both instances')
	else
		message('Class module data address is different for each instance')
	end

The result of running the program:

Getting

back to AnyAsciiFileClass, when I tried to use multiple instances I had problems because each instance was operating on the same file buffer, using the same file nameYou can see why I had a problem with multiple instances of AnyAsciiFileClass, What I needed was one file structure for each instance of the class. Only it isn't possible to declare a file layout inside a class. Files have to be declared at compile time; you can't create the on the fly at runtime (at least not without the Dynamic File Driver or DynaLib)

I created to two workarounds. One was to pass in an external file layout . That (which worked but required , but meant I had to come up with a new Ascii file declaration layout each time. The ); the other was to create some internal a predetermined number of file layouts , with corresponding class instances using those layouts, and specify which one I wanted. This and have some sort of mechanism for assigning a layout to a given instance. I'm not sure that was any improvement, as it resulted in the following clunky code:

Code Block
! Declaration
TestFile                            &DCL_System_IO_AsciiFile


    code
    TestFile &= DCL_System_IO_AsciiFileManager.GetAsciiFileInstance(DCL_System_IO_AsciiFile_InstanceNumber1)

This is really pretty awful stuff. First of all I have had to declare the file object as a reference rather than an instance. And how is anyone supposed to know they're to use this mysterious DCL_System_IO_AsciiFileManager object, not to mention that ridiculous instance number equate. And what's to prevent someone from using the same instance number twice? 

All I should really need is really wanted to be able to use the class the same way it was originally designed, only I wanted it to work for multiple instances:

Code Block
TestFile                            DCL_System_IO_AsciiFile
AnotherTestFile                     DCL_System_IO_AsciiFile
! etc

...

Pool management

I decided to treat this as a pool management problem. I needed a list of all of the available file layouts, and a way to mark a file as in use. Then in the constructor I would check the list and initialize the class instance with an available file layout. 

My first thought was to write this pool management code as a separate class. My second thought was that the code would be pretty simple, so I might as well just do it with a few procedures and a queue declared in the class source module. And my third thought was that it would probably be best after all to write the code as a separate class.

Sometimes when I create a new class the name of the class is obvious; other times I agonize over my choice, often changing it later. I'm still mulling over this one. In any case, I decided to call it DCL_System_Pool, although it's not really an object pool, more of a reference number pool. But it can server as a basis for more involved pool implementations, so for now DCL_System_Pool it is. If you're reading this years later and you don't see a class by that name in the DCL, keep looking. It's probably there somewhere. 

Here's the declaration:

Code Block
 

and here's the method code:

Code Block
 

The logic is pretty easy to follow; when you get a pool element it's marked as in use; when you're done with it and release it the flag is cleared. There's also some support for customizing error handling. 

Inside DCL_System_IO_AsciiFileManager I added five file layouts:

Code Block
 

I also added a class derived from DCL_System_Pool. This class has a constructor that initializes the pool object with five elements, one for each of five layouts:

Code Block