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 DCL_System_IO_AsciiFile, an updated version of Konrad Byers' AnyAsciiFileClass originally published in Clarion Magazine. . It'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 class. 

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

Code Block
DemoClass class,module('DemoClass.clw')
GetClassModuleDataAddress                   procedure,long
										end

and here is the CLW:

Code Block
										member
										map
										end
	include('DemoClass.inc'),once

SomeClassModuleData                     long

DemoClass.GetClassModuleDataAddress     procedure!,long
	code
	return address(SomeClassModuleData)

You can see that the CLW file contains a declaration of a LONG variable, and 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:

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:

Image Added

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 name. 

I created to workarounds. One was to pass in an external file layout. That worked but required a new Ascii file declaration each time. The other was to create some internal file layouts, with corresponding class instances using those layouts, and specify which one I wanted. This 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 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 

Code Block
TestFile                            DCL_System_IO_AsciiFile
AnotherTestFile                     DCL_System_IO_AsciiFile
! etc

There's no reason this can't work, and in fact the secret is to use the same feature that caused the problem: anything declared in the class module file is shared among all instances. That's where the instance management code needs to go.