I've decided to refactor some of my less than properly structured code.
I have a number of methods which are common to several classes. My initial implementation put them into an include file It seemed to me that the obvious thing to do would be to put them in a MyClass.cls and allow them to be inherited. So I went ahead and did that and, glory be! It actually worked with a fairly minimal amount of effort.
However...
Most of the classes that use these common methods are Forms. So I created my parent class inheriting Form.
But one of the classes that needs these common methods is a UserControl. I can't change it to a Form because its container won't allow that. And I can't change the Forms to UserControls.
I'm thinking that there has to be a relatively easy way to solve this problem but I'm not coming up with any concrete ideas.
Does anyone have a suggestion?
Hey Tom, what you are asking for is multiple inheritance. The ABL (and the MS OO languages) don't allow that.
To answer the question, we'd need to know a little more about the nature of those methods: Are those methods really required to be a member of the class? Have these methods access to private members (variables, properties, methods) of the class? Are those methods mostly executed from within the class or outside the class?
Mike
They are primarily private to the class and they mostly work with private members.
I was poking around looking at interfaces and thinking there might be some hope in that direction. But I'm not sure that that makes sense.
Interfaces would help to create a common type that could be used to access the methods of your inherited Form and the inherited UserControl (from outside the classes). Interfaces members are by definition public. So won't help you much here.
Yeah, it didn't take long to see that that wasn't going to solve my problem
For the moment I think I'll just go back to the include file. I've got bigger fish to fry right now.
I assume the common methods are used by the controls in the Form and not by the Form itself.
If this is the case you should (consider) add(ing) them to another User Control that also inherits your common behavior and then add this User Control to the form.
You are correct.
Specifically these methods all have to do with supporting behaviors that I want to see in UltraNumeric and UltraText editors. I have come to the realization that the "proper" thing to do would be for me to create my own derived versions of these controls.
I'll probably do that in the next refactoring pass that touches on this stuff.
Don't both a Form and UserControl inherit from the same superclass? How does this work in ABL? What about late binding?
In .NET both Form and UserControl inherit from Component all the way down to System.Object...
That's no different in the ABL. The ABL does not change the class hierachie of the .NET Framework at all!
System.Object inherits from Progress.Lang.Object - that's the only difference / addition.
Right, but if I am reading this right, the .NET inheritance tree doesn't help Tom since he wants to add ABL methods. No?
For some reason, I don't recall this thread from when it first came by, but it seems that the first thing we need to know, as you said earlier, is a bit more about the methods. There is something a little questionable off the top about a Form and UserControl wanting to have the same methods since they are different sorts of beast, although one might want similar signatures. If the signatures were in fact identical, but the implementations potentially different, then I might go with an interface to define the signature and two separate inheritance trees, one for forms and one for user controls.
But, again, one would like to know more about the methods.
Is this Progress.Lang namespace available on my file system? I can't find it in the GAC.
fixitchris wrote:
Is this Progress.Lang namespace available on my file system? I can't find it in the GAC.
The Progress.Lang classes are only available from within the AVM (ie ABL).
-- peter
For some reason, I don't recall this thread from when it first came by, but
it seems that the first thing we need to know, as you said earlier, is a bit
more about the methods.
>There is something a little questionable off the top
about a Form and UserControl wanting to have the same methods since they are
different sorts of beast, although one might want similar signatures.
They do both inherit from System.ComponentModel.Component, so there's clearly some commonality.
AFAIK, it's also not possible to "insert" inheritance up the class hierarchy*, so you can't simply insert your own class between Microsoft's System.ComponentModel.Component and System.Windows.Forms.Control so that all the Forms, UserControls and other controls all inherit the same behaviour.
Interfaces are the way to go for defining those methods; if you want the executable code in one class, then some sort of Delegate pattern is probably needed too.
-- peter
_* Unless you have the source code or do the special magic the AVM does.
The Progress.Lang.* classes are no .NET types. The ABL has it's own type modell. Progress.Lang.* must be implemented in the Progress runtime.
Progress.Windows.* contains .NET classes. It's types are contained in %DLC%\bin\Progress.NetUI.dll
_* Unless you have the source code or do the special magic the AVM does.
I'm pretty sure we could use IJW from C++, but not from within ABL code, right?
Ok, makes sense.
What is the purpose of Progress.NetUI?
They do both inherit from System.ComponentModel.Component, so there's clearly some commonality.
Yes, but that is a bit like saying that two ABL classes have commonality because they inherit from Progress.Lang.Object ... not quite that bad, of course, but also not a strong statement.
The key here though, I think, is that there is an existing .NET class hierarchy with a fork in it and Forms on one branch and UserControl on another branch (I don't know the actual tree, but this seems implied by prior statements). If so, then one can't really put this code into a common base without diddling with the .NET hierarchy .. correct. Therefore, it seems that, if one is doing this in ABL, one has to deal with it *after* the split, which implies two separate implementations.
As you say, if the two are truly identical methods, one might refer to a delegate, depending on what Tom actually wants to do, but if he is acting on private members, that may not be a solution.
That's part of the bridge, the magic glue between Progress and .NET.
It contains stuff like the Progress.Data.BindingSource (aka ProBindingSource) or the Progress.Windows.Form, a base .NET form that provides interoperability features between ABL windows and .NET Forms etc..
The GUI for .NET developers guide is full of stuff that Progress added in 10.2A to implement the bridge!
Do you mean what is not called ABL GUI for .NET?
Its purpose to be able to use [most] ,NET controls to create an arbitrarily nice UI, but to do all of the actual programming in ABL.
At this point, its purpose is strictly UI.
I don't know enough about ABL <> .NET but a common interface should work something like this:
class myCommonABLMethods()
method1(Component)
method2(Component)
interface ICommonComponent
Component View { get; }
class myForm: Form, ICommonComponent
Component View { get { return this; }}
class myUserControl: UserControl, ICommonComponent
Component View { get { return this; }}
maybe generics could help... http://msdn.microsoft.com/en-us/library/xwth0h0d(VS.80).aspx
Thanks guys. So the binding source is the actual glue that keeps the db context tied to the UI?
AFAIK, it's also not possible to "insert" inheritance up the class hierarchy*, so you can't simply insert your own class between Microsoft's System.ComponentModel.Component and System.Windows.Forms.Control so that all the Forms, UserControls and other controls all inherit the same behaviour.
Right, you would be forced to implement your own, overriding methods where you can.
Support for .NET classes with generics is coming in 10.2B shortly.
We will still have to wait for ABL classes with generics, unfortunately.
Hopefully, the binding source is tied to local data, not the database. One would never want the UI talking directly to the database.
Hopefully, the binding source is tied to local data, not the database. One would never want the UI talking directly to the database.
With the ProBindingSource adding a local (temp-table/prodataset) layer is pretty important. Binding to the DB works fine for reading and updating existing data. Creating new rows directly in the DB is usually painful as the ProBindingSource requires to create the record pretty early. Usually that will cause the row being released (or querying the ROWID) to the DB with default values. May cause big trouble when two users do that in parallel.
My point was that modern architectural best practice would not allow direct DB connections from a client.
I know and I'm with you on than, Ethan. My point is that is much
easier to convince long time coders when the good architecture also
solves an obvious and already faced real world issue.