Singleton train smash. Bug or by design?

Posted by Admin on 27-Aug-2008 05:08

I am trying to create a singleton to read system parameters. The problem is, if I am on the UI side, I need it to call itself (through a wrapper) on the db side, where it will access the db. I planned it as follows:

PHASE 1

CLASS SysParam in the base class.

Instance Contructor must be protected.

Static constructor must instantiate the singleton in a private static variable.

PROBLEM 1

The compiler complains that the constuctor signitures are both the same. There can surley not be any problem differentiationg between . Ok, so we rename the instance method to "GetParam", but...

PROBLEM 3:

Although the instance and its children can reference its own protected methods, the static part of the class can't, thus I need to expose the very thing I try to hide by making it PUBLIC. Ok, nobody will get access to the instance, so it does not matter. Well, turns out it does.

PHASE 4:

Implement the "GetParam" to return ? (or to run accross the AS boundry, but lets not do it before we need it).

PAHSE 5:

Create a dbaware.GetParam class which inherits from the core.GetParam. Make the empty protected constructor (with it's single phony parameter) and create a PUBLIC override for the "GetParameter" which reads the DB and returns the value.

Change the static constuctor in the base to check where we are and instantiate the correct version.

BAM!! SMASH

The static constructor in the base can not access the protected constructor in the child (because it is protected) and now I need to make this public as well. Now read this in conjunction with problem 3 and I am screwed out of the exact protection which I am trying to establish.

I do not believe that PROTECTED should hide methods and properties from others on the same level in the class. Or do we need another accessor to allow the rest of the family access without opening up to the world? I had the same problem when I created nodes in a hierarchy a few months ago. I had to make node stuff that should be protected PUBLIC simply to allow nodes to interact. (AFAIK C# allowed this with no problem when I tried a few years back.)

PROTECTED constructors can be accessed by the STATIC constructor and STATIC method and PROTECTED methods can be accessed in sub-classes (I believe that is what makes polymorphism work), but the static members can not access the sub-class constructors.

What should I make of this? I am no better off than starting the correct version of a .p persistently and making it a SUPER of the SESSION.

I do not need OO as much to do the simple stuff as I need it to do powerfull stuff that reduce the knowledge my collegues needs to do their work...

Message was edited by:

Simon Prinsloo

All Replies

Posted by Simon de Kraa on 27-Aug-2008 06:12

There is a Singleton example on page 4-57 of the OpenEdge® Getting Started: Object-oriented Programming manual.

Maybe that will give you a better start?

[View:~/cfs-file.ashx/__key/communityserver-discussions-components-files/19/8883.ObjectExplorer_5F00_v0_2C00_2.zip:550:0]

Posted by Thomas Mercer-Hursh on 27-Aug-2008 10:22

The problem is, if I am on the UI side, I need it to call itself (through a wrapper) on the db side

This is not the way I would think about it. I would say that you need a singleton on the DB side which does the access and a facade class on the UI side to access it. It isn't the same class.

Posted by Admin on 27-Aug-2008 10:41

My core framework have quite a few "workers" that run as singletons, either with all static members or with a single instance. Those work just fine.

What I want to achieve is a singleton that will automatically adapt to the deployment. On the AppServer or in Client Server it must simply access the DB, but on WebClient it must invoke a proxy to itself on the AppServer. In other words, I need it to be polymorphic without exposing its inner workings.

Posted by Admin on 27-Aug-2008 10:59

This is not the way I would think about it. I would

say that you need a singleton on the DB side which

does the access and a facade class on the UI side to

access it. It isn't the same class.

I want this to be a polymorphic construct that will automatically adapt to the deployment model.

I do not want multi-tier overhead on a client server deployment. I can easily achieve this by making an interface and use a class builder to get the correct instance type, but that leaves me with 4 source files and it expose the inner workings of both implementations to the world, even if the constuctor walk through the session's the class list (like the pre-STATIC examples in 10.1B) and make sure it is the only instance of the interface.

Besides, I discovered that my problem goes wider than that.

Our current package is a fat client with 3500+ programs (all CHUI) and highly configurable with parameters.

On the objects where Busness Rules (can ever) be configurable, we want use an abstact or default base class with a protected constructer, and a static New() method that will check the system parameters and instantiate the correct sub-class and return that version. This will guarntee that the class is always instantiated through this "class builder" method. The problem is that the static New() can only access the protected local constructor, thus I need to make the contructor of any inherrited class public for the "class builder" to be able to create it. This guarantees that some one will from time to time instantiate the sub-class directly somewhere, which may backfire only years later when "another way" is created and some programs keep following the "old way".

Posted by Thomas Mercer-Hursh on 27-Aug-2008 11:45

I want this to be a polymorphic construct that will automatically adapt to the deployment model.

Well, sounds nice, but I don't think that is the way things are done. And, I don't see how it exposes any inner workings. The facade simply takes the place of the real object and passes through the method calls to the real object. The rest of the application on the UI side is unaware whether it is dealing with the facade or the real thing and the real thing is unaware whether requests are coming from the application or the facade.

I do not want multi-tier overhead on a client server deployment.

Huh? Either way you have a call across the wire and that is the expensive piece. The only difference between having one class that plays both roles versus using a facade is that the one class has a whole bunch of logic that it never uses because it is making calls to the real object on the DB side. I.e., it needs to have both real and facade logic.

Note that it is perfectly reasonable to have a facade that caches data after the first call, if that is appropriate.

There may be other approaches to the configuration issue. E.g., I recently had an entertaining discussion related to this on the Google UML forum at http://groups.google.com/group/UMLforum in which the other guy described a system of what amounts to dynamic properties. You might want to take a look at that discussion for ideas ... although it is pretty long.

Posted by Admin on 27-Aug-2008 12:49

Thomas, it seems so simple when you express it. Sure whish I concentrated more when they tried to learn me the Khaki-language. Now all of you suffer because of my poor English.

I am not trying to make a "one class do both" object. I built the facade, as you call it, as a singleton. Then I wanted to inherit from it to build the real object, because most logic (except for one method accessing the db) are the same. The static method that instantiates the singleton was supposed to create an instance of either the facade itself or of the sub-class. That way, the appservers and host based CHUI sessions would not "RUN wrapper.p ON hAppServ" when hAppServ = SESSION.

My only problem is that anybody can now instantiate the sub class directly (because the ABL force me to expose the constuctor) which may go undetected untill it is too late. But then again, the risk for this on a singleton is propably very low, since it is more work to do it wrong than it is to do it right.

The problem becomes more severe for a normal (non-singleton) object when I try to use a static "class builder" method in a base "abstact" class to create the correct sub-type intance based on system configuration. There the temptation to invoke the subtype directly may be too big for some people, thus when we implement a different version (normally an option for an alternate process flows) , the programs that bypass the builder will malfunction. I am after all trying to create a programmer-proof methodology here.

Posted by Thomas Mercer-Hursh on 27-Aug-2008 13:37

Well, it sounds a bit more reasonable now, but .... I'm not sure. Have you considered creating a common base class and have the facade and the real one both inherit from it? Would that make any difference? I find the idea of a constructor instantiating different classes a bit odd.

Posted by Admin on 28-Aug-2008 01:07

Well, it sounds a bit more reasonable now, but ....

I'm not sure. Have you considered creating a common

base class and have the facade and the real one both

inherit from it? Would that make any difference? I

find the idea of a constructor instantiating

different classes a bit odd.

With contructor I mean a static class builder method that creates the instance, which may or may not be the static constructor in the case of a singleton.

I did consider a common "abstract" base class, especially for the non-singletons. It is currently the only "clean" way to do it. It does however make a difference, because "class builder", (being code that needs the instance, an independent class builder type or a static method in the base class), needs the constructors of the implementation to be public. I would prefer to make the constructors of the implementation less public, but still accessible to the class builder. I figured a static builder method in the base with protected constructors in the implementations (they are after all in the inheritance hierarchy) would do the trick, but it does not.

Posted by Evan Bleicher on 10-Sep-2008 16:03

The thread has dealt with numerous linguistic and design issues related to ABL’s implementation of static class members. I would like to clarify four issues raised in this thread.

#1:

PROBLEM 1, asserted that the compiler complains if the signature of a static constructor and instance constructor are the same. This is not the case.

The following snippet of code demonstrates this capability. In this code both the static and instance constructors take no parameters. Since it is illegal for a static constructor to take any parameters this is the only relevant example. This code example should compile successfully in your environment. If you are experiencing an issue with this, log an issue with technical support.

CLASS static-test1:

DEFINE PUBLIC STATIC PROPERTY Instance AS CLASS static-test1 NO-UNDO

GET.

PRIVATE SET.

CONSTRUCTOR PRIVATE static-test1( ):

/* Make the constructor private so it cannot be called from outside of the class */

MESSAGE "In instance constructor" VIEW-AS ALERT-BOX.

END CONSTRUCTOR.

CONSTRUCTOR STATIC static-test1( ):

MESSAGE "In static constructor" VIEW-AS ALERT-BOX.

/* Create the one single instance when the static constructor is called */

static-test1:Instance = NEW static-test1( ).

END CONSTRUCTOR.

END CLASS.

#2:

PROBLEM 2, asserted that the compiler generates an error if a static method has the same signature as an instance method, but the compiler allows two instance methods to have the same signature. This is not the case. The ABL does not use static to differentiate method signatures. This is consistent with other object oriented languages. All methods with the same name in an ABL class must have unique signatures.

If you add the following methods to the above class, the class will continue to compile successfully. If you make the signature the same, by removing INPUT ch as CHAR, from the instance version of method1, the compilation process will fail. The compiler will generate an error even if you remove the static keyword from the first version of the method1 and therefore having two instance methods with the same name and same signatures. For overloading to work properly all methods must have unique signatures.

METHOD PUBLIC STATIC VOID method1 (INPUT i AS INTEGER):

END METHOD.

METHOD PUBLIC VOID method1 (INPUT i AS INTEGER, INPUT ch AS CHAR):

END METHOD.

#3:

Under Phase 5, the posting states: I do not believe that PROTECTED should hide methods and properties from others on the same level in the class.

This is an interesting point. ABL has implemented an object-level privacy model and other object oriented languages have implemented a class-level privacy model. We are discussing this issue within the development team. Did I properly understand your concern?

#4:

I may be misinterpreting the posting from August 27th, 2008 at 11:59 AM, which asserted the polymorphism is not working for statics. Consistent with other object oriented languages it is not the case that polymorphism works the same with static methods as it does with instance methods.

Posted by Admin on 10-Sep-2008 16:09

This is an interesting point. ABL has implemented an

object-level privacy model and other object oriented

languages have implemented a class-level privacy

model. We are discussing this issue within the

development team. Did I properly understand your

concern?

Other languages have also implemented a package level (friend) protection model. I know this is probably hard to translate to the ABL as there is no real packaging of classes (the actual packages are copied together during deployment so I could simply create a class in the same directory and for the ABL it's part of the same package).

But that's something I'd like to see in a future use release. Please keep that in mind as well, when discussing additional protection modifiers.

This thread is closed