Collections

Posted by jmls on 04-Aug-2008 01:38

Is there anything in this release that helps manage collections ? I was able to compile the following, and was living in hope for a few seconds ..

DEF PUBLIC PROPERTY Node AS CLASS node EXTENT NO-UNDO GET . PRIVATE SET .

node[1] = new node ().

node[1]:text = "foo".

message node[1]:Text view-as alert-box.

so, it all compiles. But when you run, you get message 11389. Bummer ; It would have made collections easy !

All Replies

Posted by Simon de Kraa on 04-Aug-2008 02:18

Maybe you could use a temp-table of Progress.Lang.Object and write your own class methods like for example with System.Collections.ArrayList?

Posted by jmls on 04-Aug-2008 02:28

maybe - I was hoping that PSC would allow me to do it the easy way

Posted by Admin on 04-Aug-2008 05:32

What you tried in your code was not Collection support. It was support for property indexers... AFAIK that has been discussed and delayed for a later release.

I can live with that FOR NOW...

Why don't you go with any of the .NET collection classes? Even ABL classes, that inherit from System.Object or any other appropriate .NET class can be added to those collections and lists.

Posted by jmls on 04-Aug-2008 05:53

What you tried in your code was not Collection

support. It was support for property indexers...

AFAIK that has been discussed and delayed for a later

release.

Thanks for the enlightenment.

I can live with that FOR NOW...

Why don't you go with any of the .NET collection

classes? Even ABL classes, that inherit from

System.Object or any other appropriate .NET class can

be added to those collections and lists.

So, if I were to add a number of 4GL classes (let's say my "node" class) how would I access them

In VB I would say TopClass.Nodes.Item(n).Text or even TopClass.Nodes(n).text

so, if I made "Nodes" a VB collection and added my "nodes" class to the collection I would be able to say

TopClass:Nodes:Item(n):Text or TopClass:Nodes(n):Text ?

 * jmls rushes off to try

Posted by Simon de Kraa on 04-Aug-2008 08:03

Why don't you go with any of the .NET collection

classes? Even ABL classes, that inherit from

System.Object or any other appropriate .NET class can

be added to those collections and lists.

Huh, so System.Collections.ArrayList works for ABL classes as well!

Posted by Simon de Kraa on 04-Aug-2008 08:22

DEFINE VARIABLE r1 AS CLASS System.Collections.ArrayList.

DEFINE VARIABLE r2 AS CLASS test.

r1 = NEW System.Collections.ArrayList().

r2 = NEW test().

r1:ADD(r2).

r2 = NEW test().

r1:ADD(r2).

MESSAGE r1:item[1]:equals(r2) /* yes */

VIEW-AS ALERT-BOX INFO BUTTONS OK.

/* test.cls */

CLASS test INHERITS System.OBJECT.

END CLASS.

Posted by jmls on 04-Aug-2008 08:29

are you saying that this works, or doesn't ?

Posted by Admin on 04-Aug-2008 08:35

i don't know, if there is an issue. Are you aware that .NET starts to count at 0?

Posted by jmls on 04-Aug-2008 08:41

heh. That's what I was alluding to.

Posted by jankeir on 04-Aug-2008 09:02

If it works it's another reason to have support for .NET in the appserver (after FCS offcourse.)

And if the support would also work for mono it would even work on unix appservers! But I'm probably asking a lot now...

Posted by Thomas Mercer-Hursh on 04-Aug-2008 11:00

Maybe you could use a temp-table of Progress.Lang.Object and write your own class methods

Something like this, you mean?

http://www.oehive.org/CollectionClasses

Posted by Simon de Kraa on 04-Aug-2008 12:31

Yes, it works...

But the DYNAMIC-CAST does not work anyone knows why?

DEFINE VARIABLE rArray AS CLASS System.Collections.ArrayList.

DEFINE VARIABLE rTest1 AS CLASS test1.

DEFINE VARIABLE rTest2 AS CLASS test2.

DEFINE VARIABLE rObj AS CLASS System.OBJECT.

DEFINE VARIABLE j AS INTEGER NO-UNDO.

/* create */

rArray = NEW System.Collections.ArrayList().

rTest1 = NEW test1().

rArray:ADD(rTest1).

rTest2 = NEW test2().

rArray:ADD(rTest2).

/* be aware that .NET starts to count at 0 */

DO j = 0 TO rArray:COUNT - 1:

MESSAGE

rArray:ITEM:tostring()

rArray:ITEM:equals(rTest2)

VIEW-AS ALERT-BOX INFO BUTTONS OK.

END.

/* pick a random item */

rObj = rArray:ITEM.

/* cast to correct type and call method */

DYNAMIC-CAST(r3, rObj:tostring()):testme(). /* error */

/CAST(rObj, "test1"):testme()./

/* test1.cls

CLASS test1 INHERITS System.OBJECT.

METHOD PUBLIC VOID testme():

MESSAGE THIS-OBJECT:tostring()

VIEW-AS ALERT-BOX INFO BUTTONS OK.

END METHOD.

END CLASS.

*/

/* test2.cls

CLASS test2 INHERITS System.OBJECT.

METHOD PUBLIC VOID testme():

MESSAGE THIS-OBJECT:tostring()

VIEW-AS ALERT-BOX INFO BUTTONS OK.

END METHOD.

END CLASS.

*/

Posted by Simon de Kraa on 04-Aug-2008 12:40

Maybe you could use a temp-table of

Progress.Lang.Object and write your own class methods

Something like this, you mean?

http://www.oehive.org/CollectionClasses

Exactly. But I guess to can use the System.Collections as well...

Posted by Shelley Chase on 04-Aug-2008 12:47

Hi Julian,

This should work since it is just an ABL array of .NET classes. In your code snippet, the array has not been initialized to a size so it doesn't have any "storage area" yet. You need to set the extent (size) before doing the assignment:

node[1] = new node ().

And since this is an ABL array, not a .NET array, it's index starts at 1.

Like others are saying, you can put .NET classes in ABL arrays but you cannot put ABL classes into .NET arrays/collections.

-Shelley

Posted by Admin on 04-Aug-2008 14:25

Like others are saying, you can put .NET classes in

ABL arrays but you cannot put ABL classes into .NET

arrays/collections.

Hi Shelley,

so, is adding an ABL class that inherits from System.Object something that will NOT be supported? It works too well for me to believe!

I always thought, that an ABL class that inherits from a .NET type can be used anywhere the base .NET type can be used. But for the .NET side of the bridge, the ABL class will look exactly like the .NET class, so extending members from the ABL side will not be visible on the .NET side.

The whole inheritance from .NET controls would be completly useless, if I could not add ABL classes (inherting at least from System.Object) to the Controls (well here it should be System.Windows.Forms.Control) collection of a Form or the Items collection of a ComboBox.

Or am I misundertanding your statement, as you do not consider an ABL class that inherits from System.Object an ABL class anymore?

Mike (confused)

Posted by Admin on 04-Aug-2008 14:27

Note on the AppServer. There's where you need something home grown like Thomas' Collection classes or something similar (i.e. based on a temp-table with a Progress.Lang.Object field).

Posted by Shelley Chase on 04-Aug-2008 14:36

Hi Mike,

Sorry for the confusion. You can inherit from .NET classes in the ABL. And from .NET, they look like they were written in .NET.

I was trying to make the point that a class that is pure ABL and does not have System.Object in its class hierarchy cannot be used as a .NET object. For example a pure ABL class cannot be put into a System.Array. Make sense?

-Shelley

Posted by Admin on 04-Aug-2008 14:45

Absolutely.

Looks like we need a good name for ABL classes inheriting from System.Object to avoid confusion. I still consider them ABL classes as the majority of the creativity that I spend on making them what they are is developed in ABL code. While in the ABL, the .NET part is a black (or at least dark grey) box.

How about a hybrid or magic class

Mike (a stone has fallen off my heart!)

Posted by Shelley Chase on 04-Aug-2008 14:58

I believe the documentation for 10.2A will refer to them as a hybrid user-defined class or hybrid class for short.

Posted by rbf on 04-Aug-2008 15:08

How about ABL.NET class?

(I am just a simple mind)

Posted by Admin on 04-Aug-2008 15:12

I like simple minds (forget about me!)

ABL.NET get's my vote!

Posted by Simon de Kraa on 04-Aug-2008 15:18

Note on the AppServer. There's where you need

something home grown like Thomas' Collection classes

or something similar (i.e. based on a temp-table with

a Progress.Lang.Object field).

Understood.

Any idea why the DYNAMIC-CAST does not work?

DYNAMIC-CAST(r3, rObj:tostring()):testme(). /* error */

-or-

DYNAMIC-CAST(r3, "test1"):testme(). /* error */

Posted by Simon de Kraa on 04-Aug-2008 15:19

How about ABL.NET class?

(I am just a simple mind)

+1

Posted by Admin on 04-Aug-2008 15:30

got my vote aswell, clear and simple.

Posted by Admin on 04-Aug-2008 15:40

First: I don't see a variable definition for r3, so I don't know it's type.

Second: rObj:ToString() returns (if not overridden somewhere) a pseudo reference value that consists of the type name and something like a handle. So it can't be a string returning the type/class name.

Dynamic cast requires a valid type name. As it's second argument.

By the way: I don't thing I'll ever use/need DYNAMIC-CAST at all! At least as long as we don't have dynamic invokation of methods in the ABL at all. The combination of TYPE-OF and CAST works better for me.

Posted by Admin on 04-Aug-2008 15:45

DYNAMIC-CAST(r3, "test1"):testme(). /* error */

Quote from the reference (online help):

"You cannot use the DYNAMIC-CAST function to cast an object reference to a subclass and invoke a method defined in that subclass using the following syntax:"

I guess this is because the compiler can not know the sub-class that will be passed at runtime and so it can't know anything about validity of the testme() method.

No chance to break strong typing with DYNAMIC-CAST! Great, isn't is?

Posted by Simon de Kraa on 04-Aug-2008 16:06

Sorry, r3 should be rObj:

DYNAMIC-CAST(rObj, rObj:tostring()):testme(). /* error */

In the example rObj:ToString() returns either "test1" or "test2".

I thought this could be done dynamically by a one-liner but I guess the only way to do this is like you said with the TYPE-OF and CAST for each type of class in the array of System.Object.

IF TYPE-OF(rObj, "test1") THEN

CAST(rObj, "test1"):testme().

IF TYPE-OF(rObj, "test2") THEN

CAST(rObj, "test2"):testme().

...

IF TYPE-OF(rObj, "testN") THEN

CAST(rObj, "testN"):testme().

Posted by Thomas Mercer-Hursh on 04-Aug-2008 16:17

Is it that the dynamic cast fails or is it that you are trying to run a method on the dynamic cast result that fails. What happens if you move the testme() to a second line?

Posted by Simon de Kraa on 05-Aug-2008 00:56

Doesn't work. You have to cast again to make it work...

DEFINE VARIABLE rTmp AS CLASS System.OBJECT.

rTmp = DYNAMIC-CAST(rObj, rObj:ToString()).

rTmp:testme(). /* Could not locate element 'testme' in class 'System.OBJECT'. (12927) */

CAST(rTmp, "test1"):testme(). /* ok */

Posted by Thomas Mercer-Hursh on 05-Aug-2008 11:09

So, in this sequence, it compiles, but fails in execution on the testme line? That seems very peculiar indeed. One would expect the dynamic-cast to either produce a result or to throw an error.

Posted by Simon de Kraa on 05-Aug-2008 11:45

The following syntax is not allowed:

DYNAMIC-CAST( object-reference, object-type-name ):method-name( parameters ).

So once you have dynamically cast the object you have to do a static CAST again to be able to call the method testme().

So I think this means you cannot use the ArrayList class in a generic way to store ABL classes without knowing in advance what exact classes you are using. If you are going to call methods in those classes that is...

Ah well, it is more likely you know in advance the exact classes and use TYPE-OF and a static CAST to call the methods anyway... (like Mike said a few posts back)

I would like to see a good example of the DYNAMIC-CAST statement though...

Posted by Thomas Mercer-Hursh on 05-Aug-2008 12:08

A good example is right ... from that code, it is not clear what, if anything, the dynamic cast is actually doing.

Posted by Admin on 05-Aug-2008 12:51

I would like to see a good example of the

DYNAMIC-CAST statement though...

I owe you a beer for this question!

I really see no need why we have the DYNAMIC-CAST function in the ABL. But maybe all the customers using OOABL in this forum are just blind here.

This thread is closed