SCL Collection Class question (v8)

SCL Collection Class question (v8)

Post by Scot » Thu, 07 Feb 2002 09:16:46



I am using the collection class to store a group of objects that I
define in another class.  I have no problem using the _add method of
the collection class to fill the collection.  However, what is the
best way to retreive an object from the collection based on a the
object's name attribute?  I could iterate through the list in the
ITEMS attribute of the class until I find the name (2 lists deep in
the ITEMS attribute).  Would it be nice to have an _getItem method
with an num or char identifier as an argument to return the object?

Thanks,
Scott

For example:
--------------
My class that will be in the collection
(mylib.mycatalog.policy.class):

/*---START--------------------------------------------------*/
     Class Policy;                                                  
           Public char ID;                                      
           Public char Desc;
           Public num  Type;
     EndClass;
/*---END----------------------------------------------------*/

My SCL code:

/*---START--------------------------------------------------*/
dcl mylib.mycatalog.Holder.class myHolder=_new_ Holder();
import mylib.mycatalog.policy.class;                              

INIT:
     dcl mylib.mycatalog.policy.class myPolicy;                      

     *Create one item;
     myPolicy=_NEW_ Policy();
     myPolicy.ID='Strict';                  
     myPolicy.Desc='A very strict policy.';
     myPolicy.Type=1;                                      

     * Add the item to the collection;
     myHolder.Policies._add(myPolicy);

     * Create a new item;
     myPolicy=_NEW_ Policy();
     myPolicy.ID='Free';
     myPolicy.Desc='Do what you want.';
     myPolicy.Type=2;    

     * Add the 2nd item to the collection;
     myHolder.Policies._add(myPolicy);                

     * Get the contents (as a list);
     dcl list myItems ={};      
     myItems=myHolder.Policies.Items;

     * How can I get the object based on its ID?;
     * Such As:
     *    dcl mylib.mycatalog.policy.class AnotherPolicy;
     *    AnotherPolicy=myHolder.Policies._getItem('Strict');

return;
/*---END----------------------------------------------------*/

 
 
 

SCL Collection Class question (v8)

Post by David L. Wa » Thu, 07 Feb 2002 10:39:10


Scott,

Wow - an SCL question.  It's been many moons since we have seen one on the
list, especially an OOP question.  The solution to your problem is to
subclass the collection class and add your own method to do this since the
original class does not have such a method.  In fact, it can't have a method
like this because you can put any kind of item into the collection and not
all will have some kind of "ID" attribute like your policy class.  But
assuming that you only have policy objects in your container, create your
own collection class like this:

/*---START--------------------------------------------------*/
class collection extends sashelp.classes.collection;

getItemByID: method id:char return=object;
  Dcl num i;
  Dcl object rtrn itemObj;
  i=1;
  do while (i<=listlen(items) and not rtrn);
    if itemtype(items,i)='O' then do;
      itemObj=getitemo(items,i);
      if upcase(itemObj.ID)=upcase(id) then rtrn=itemObj;
    end;
    i=i+1;
  end;
  return rtrn;
endmethod;

endclass;
/*---END----------------------------------------------------*/

And use it likethis:

/*---START--------------------------------------------------*/
Dcl collection c = _new_ collection();
Dcl policy myPolicy = _new_ policy();
Dcl policy myPolicy2;
init:
  myPolicy.ID='Test';
  c._add(myPolicy);
  rc=putlist(c.items,'',0);
  myPolicy2=c.getItemByID('Test1');
  put myPolicy2=;
  myPolicy2=c.getItemByID('Test');
  put myPolicy2=;
return;
/*---END----------------------------------------------------*/

HTH
David Ward

-----Original Message-----

Sent: Tuesday, February 05, 2002 7:17 PM

Subject: SCL Collection Class question (v8)

I am using the collection class to store a group of objects that I
define in another class.  I have no problem using the _add method of
the collection class to fill the collection.  However, what is the
best way to retreive an object from the collection based on a the
object's name attribute?  I could iterate through the list in the
ITEMS attribute of the class until I find the name (2 lists deep in
the ITEMS attribute).  Would it be nice to have an _getItem method
with an num or char identifier as an argument to return the object?

Thanks,
Scott

For example:
--------------
My class that will be in the collection
(mylib.mycatalog.policy.class):

/*---START--------------------------------------------------*/
     Class Policy;
           Public char ID;
           Public char Desc;
           Public num  Type;
     EndClass;
/*---END----------------------------------------------------*/

My SCL code:

/*---START--------------------------------------------------*/
dcl mylib.mycatalog.Holder.class myHolder=_new_ Holder();
import mylib.mycatalog.policy.class;

INIT:
     dcl mylib.mycatalog.policy.class myPolicy;

     *Create one item;
     myPolicy=_NEW_ Policy();
     myPolicy.ID='Strict';
     myPolicy.Desc='A very strict policy.';
     myPolicy.Type=1;

     * Add the item to the collection;
     myHolder.Policies._add(myPolicy);

     * Create a new item;
     myPolicy=_NEW_ Policy();
     myPolicy.ID='Free';
     myPolicy.Desc='Do what you want.';
     myPolicy.Type=2;

     * Add the 2nd item to the collection;
     myHolder.Policies._add(myPolicy);

     * Get the contents (as a list);
     dcl list myItems ={};
     myItems=myHolder.Policies.Items;

     * How can I get the object based on its ID?;
     * Such As:
     *    dcl mylib.mycatalog.policy.class AnotherPolicy;
     *    AnotherPolicy=myHolder.Policies._getItem('Strict');

return;
/*---END----------------------------------------------------*/


 
 
 

SCL Collection Class question (v8)

Post by Richard A. DeVenezi » Fri, 08 Feb 2002 15:37:47



Quote:> I am using the collection class to store a group of objects that I
> define in another class.  I have no problem using the _add method of
> the collection class to fill the collection.  However, what is the
> best way to retreive an object from the collection based on a the
> object's name attribute?  I could iterate through the list in the
> ITEMS attribute of the class until I find the name (2 lists deep in
> the ITEMS attribute).  Would it be nice to have an _getItem method
> with an num or char identifier as an argument to return the object?

The Collection Class is principally a class for simplified operations with
an SCL list, with the primary advantage over SCL lists of having an apply()
method.

If you are dealing with objects only one class in the collection, consider
storing the object references as named items of type object in an SCL list.

If your .ID values are unique, they can be used for the item name that is
passed to the SCL function setNitemO().  If ID values can be repeated you
will have to use SCL function insertItemO() with a name argument.

assuming unique ID's
dcl list holder = {};
...
myPolicy=_NEW_ Policy();
...
rc = setNitemO (holder, myPolicy, myPolicy.ID);
...
myPolicy=_NEW_ Policy();
...
rc = setNitemO (holder, myPolicy, myPolicy.ID);
...
...
...
strictPolicy = getNitemO (holder, 'Strict');

You can implement this simplified behaviour in your own holder class with
two methods, add() and get(), and a class variable for the list.

*********************************************************************

A simple examination of the Collection Class (which is documentation
challenged) can be done with this example.  You will note that the list of
items that _add adds to is of unnamed items, and thus note useful for
getNitemX() SCL functions.

---
import sashelp.fsp.sasfile.class;
import sashelp.classes.collection.class;

init:
  dcl collection c = _new_ collection();

  do i = 1 to 4;
    dcl sasfile sf = _new_ sasfile();
    c._add (sf);
  end;

  c._dump();
  call putlist (c._getItems(), '', 0);
return;
---

*********************************************************************

A read of the Collection class _getItems(predicate) method has some teaser
information.  Apparently another class, that contains a predicate method
(whatever that is), can be used to make a determination of whether or not a
item in the collection should be returned by getItems().

A mild bit of experimentation shows that a class with a method named
"predicate" does indeed have it's predicate() method called from
_getItems(<instance of class with predicate method>) for each item in the
collection.  Further experimentation shows that predicate() is passed two
arguments, the first is an object identifer and the second is a return flag
that indicates whether the object should be returned by the Collection class
_getItems(predicate) method.

Here is a working example:

Match.class is the example but can be any class you implement.
The logic in the predicate() method where you implement the _getItems()
inclusion/exclusion logic.
In the example the logic revolves about an object's name, in Scott's case it
would involve the value of an object's .ID attribute.

----------------------------------------------
--- catalog entry: work.rad.matchclass.scl ---
----------------------------------------------
class work.rad.match.class
  extends sashelp.fsp.Object.class;

dcl char m_textToMatch;

* constructor is method with same name as class;
* do not need to override since the parent (Object) does not have
* constructor with signature (C)V;
match: public method textToMatch:char ;
  m_textToMatch = textToMatch;
endmethod ;

predicate: public method objectToCheck:object objectMatches:O:num;

  if objectToCheck.name = m_textToMatch then
    objectMatches = 1;

endmethod;

endclass;
----------------------------------------
# issue command: compile;save;saveclass

----------------------------------------
--- catalog entry: work.rad.rad.scl ----

----------------------------------------
import sashelp.fsp.sasfile.class;
import sashelp.classes.collection.class;
import work.rad.match.class;

init:
  dcl collection c = _new_ collection();

  dcl char randomNames[*] = ( "Alice", "Bob", "Charles", "Darwin" );

  do i = 1 to 4;
    dcl sasfile sf = _new_ sasfile();
    sf.name = randomNames[i];
    c._add (sf);
  end;

  c._dump();
  call putlist (c._getItems(), '', 0);

  * the new argument (Bob) will be used by the match.class predicate()
method;
  declare match M = _new_ match ("Bob");

  matches = c._getItems(M);
  call putlist (matches, '', 0);
return;

----------------------------------------
# issue command: compile;testaf

You will note in the LOG, the last AF will show a list with one item, an
object whose name attribute value is Bob. A match made in heAFen :)

You can improve the reuseability of the match.class in several ways, I will
outline one.
Instead of passing in the constructor, a single value, you could pass in a
two values:
- argument1, which is the attribute name to be matched
- argument2, which is the attribute value to be matched
The predicate method would then check whether the object has an attribute
that matches argument1 and if so whether the attributes value matches
argument2.

Go wild! Pass in regular expressions!

Logic would dictate that the Collection class _apply(action) method works in
the same way.

--
Richard A. DeVenezia
http://www.devenezia.com

 
 
 

1. Problem with SETCAM (SCL V8)

Hello,

I built a new object with a new attribute "red".
Correct values for red are from 0 to 255.

When I use my object and try to set via code a value not between 0 and
255,
my object correctly trigger that error and stop execution:

toto.red = 4556;
Log==>
Error:
Valid values are from 0 to 255.
Parameters passed to method _SETATTRIBUTEVALUE:
  1 (Character Literal) = 'red'
  2 (Numeric Expression $T0) = 4556
Program returning prematurely at line 8
AF Program: SASAF.COLORS.TEST.FRAME

BUT when the attribute value is linked to the numeric value of a
TextEntry
and when I enter :
textentry1.text = 1234;

The error is not traped and the attribute do not take the value of
1234.

Here's the custom access method for the object attribute:

setcamRed: protected Method attrVRed:update:num return=num;
   attrVRed=int(attrVRed);
   if attrVRed >= 0 and attrVRed <= 255 then do;
      _SELF_.SB_RED.value = attrVRed;
      _SELF_.setColor(put(attrVred, hex2.) || put(_SELF_.green, hex2.)
|| put(_SELF_.blue, hex2.));
      return(0);
   end;
   else do;
      put 'Hello';
      _SELF_.errorMessage='Error:' || '0A'x || 'Valid values are from
0 to 255.';
      return(1);
   end;
EndMethod;

I can see "Hello" in the log but the application does not understand
the return code of 1 and do not report the error message.

Any clue?

Xavier

2. migrating data from 4.0.16 to 4.0.17

3. Populating a listbox with an SCL List in V8

4. Help Please, with home network

5. SCL v8 problem with '--'

6. paper-to-digital conversion

7. Collection class wrapper problem.

8. Problems with Windows Media Player 8 under PPC2002

9. Java/CORBA Collection Classes

10. PB Collection Classes

11. UML Class Diagram : C# Collections

12. Modeling Collection Classes

13. Legacy Class, implementation with class A in class B parameter...