Where to put statics

Posted by jmls on 10-Jan-2011 04:58

As a follow-on from my previous post, something else I noticed in yii, which seemed interesting was the following

As progress doesn't have CONST or ENUM , I have been using static properties to define certain "types". For example, a type of phone number

CLASS enum.PhoneType:

     DEF PUBLIC STATIC PROPERTY landline AS CHAR INIT "landline" NO-UNDO GET . PRIVATE SET.

     DEF PUBLIC STATIC PROPERTY mobile AS CHAR INIT "landline" NO-UNDO GET . PRIVATE SET.

END CLASS.

so now I can refer to

MyPhone = New Phone().

IF MyPhone:PhoneType EQ enum.PhoneType:landline ...

Now, yii seems to define the CONST in the model itself as a static. So, If I do that, I could have

MyPhone = New Phone().

IF MyPhone:Type EQ Phone:landline ...

I can't see any downside with this, as the "type" properties are still static, so there is only ever one instance of the property, and it removes the need for a seperate enum class.

Any comments ?

All Replies

Posted by Peter Judge on 10-Jan-2011 07:57

As progress doesn't have CONST or ENUM , I have been using static properties

to define certain "types". For example, a type of phone number

CLASS enum.PhoneType:

DEF PUBLIC STATIC PROPERTY landline AS CHAR INIT "landline" NO-UNDO GET

. PRIVATE SET.

DEF PUBLIC STATIC PROPERTY mobile AS CHAR INIT "landline" NO-UNDO GET .

PRIVATE SET.

END CLASS.

so now I can refer to

MyPhone = New Phone().

IF MyPhone:PhoneType EQ enum.PhoneType:landline ...

Now, yii seems to define the CONST in the model itself as a static. So, If I

do that, I could have

MyPhone = New Phone().

IF MyPhone:Type EQ Phone:landline ...

I can't see any downside with this, as the "type" properties are still

static, so there is only ever one instance of the property, and it removes

the need for a seperate enum class.

I tend to use separate Enum classes, although I have used the constant-in-class approach before. I prefer the separate class approach since you can now use inheritance if you desire: define a parameter as Enum and pass any kind of Enum.

The main reason though, is that I can do stuff like this:

CLASS enum.PhoneType:

DEF PUBLIC STATIC PROPERTY landline AS enum.PhoneType NO-UNDO GET. PRIVATE SET.

DEF PUBLIC STATIC PROPERTY mobile AS enum.PhoneType NO-UNDO GET. PRIVATE SET.

Constructor static PhoneType():

Landline = new PhoneType().

Mobile = new PhoneType().

End constructor.

END CLASS.

Now I can define an interface with

Method void foo(input poPhone as enum.PhoneType)

and be typesafe.

If you want to have a string value associated with enum.PhoneType:Landline, you can have a property/variable in the enum class that stores this, and shows it when doing a ToString(). But with the enum approach you really don't need a string value, since the object reference is always unique within a session.

Using chars means you can use a character value as a parameter and you can still do comparisons etc with string values (instead of proper objects):

pcPhone eq enum.PhoneType:Landline.

as opposed to a more object-y comparison

poPhone:Equals(enum.PhoneType:Landline) ,

where the comparison is done on something which I as the writer of that line of code don't know or care about.

Do you have concerns about having separate classes for your enums?

-- peter

Posted by Thomas Mercer-Hursh on 10-Jan-2011 11:34

I would think that one of the big differences is that a separate enum class is referencable from many places, but something defined only within the model is only referencable in the model.

Posted by jmls on 10-Jan-2011 12:02

Perhaps I didn't make myself clear enough

enums: yes, can be referenced many places. But so could this code

CLASS MyModel INHERITS BaseModel:

DEF STATIC PROPERTY TypeB INIT "B" NO-UNDO GET . SET .

DEF STATIC PROPERTY TypeA INIT "A" NO-UNDO GET . SET .

DEF PROPERTY Name AS CHAR NO-UNDO GET . SET .

DEF PROPERTY Type AS CHAR NO-UNDO GET . SET .

METHOD PUBLIC VOID Save():

END METHOD.

END CLASS.

so, I can say

SomeObject = NEW MyModel()

SomeObject:Type = MyModel:TypeA

or

Message "MyModel TypeA is defined as" MyModel:TypeA view-as alert-box.

IOW it can be used anywhere as well

On 10 January 2011 17:34, Thomas Mercer-Hursh

Posted by Thomas Mercer-Hursh on 10-Jan-2011 12:26

OK, that isn't what I thought you meant.  My first reaction is to dislike the word Type here since it might lead to confusion with object type.   I.e., it is a difference in state or kind rather than type.

But, I think my remark still stands.  This approach does not provide you with an enum equivalent for testing the kind of object, i.e., there is no list of possible states.

Posted by Admin on 10-Jan-2011 12:27

IOW it can be used anywhere as well

 

I would also tend to excluse the Enum's from the rest of the functionality, keep them separate (by the way, I use type-safe Enums - like in .NET - where the parameter I pass is not a CHARACTER or INTEGER).

Keeping them external allows them to be a type of it's own.

Posted by jmls on 10-Jan-2011 12:42

As I mentioned, that's the way I currently use enums. I was just

curious that the yii framework handles them inside the model rather

than a separate class. (php does not have native enums either)

Julian

Posted by Admin on 10-Jan-2011 13:07

FYI, this is my Enum pattern for the ABL:

http://blog.consultingwerk.de/consultingwerkblog/2010/08/a-pattern-for-enums/

In the real world, I'm using include files for the Enum member static property definition.

EnumMember.i looks like this:

    DEFINE PUBLIC STATIC PROPERTY {1} AS {3} NO-UNDO

    GET:

        IF NOT VALID-OBJECT ({3}:{1}) THEN

            {3}:{1} = NEW {3} ({2}, "{1}") .

        RETURN {3}:{1} .          

    END GET .

    PRIVATE SET.

As sample enum member's definition in a class inheriting Consultingwerk.Enum looks like this:
    /* Static members */   
    {Consultingwerk\EnumMember.i Add 1 TableIOActionEnum} 
    {Consultingwerk\EnumMember.i Cancel 2 TableIOActionEnum} 
    {Consultingwerk\EnumMember.i Copy 3 TableIOActionEnum} 
    {Consultingwerk\EnumMember.i Delete 4 TableIOActionEnum} 
    {Consultingwerk\EnumMember.i Save 5 TableIOActionEnum} 
    {Consultingwerk\EnumMember.i Update 6 TableIOActionEnum} 
And now shoot me :-)

Posted by jmls on 11-Jan-2011 05:52

Right. So you are saying that each enum is an object, with a value and a label. This means that you can compare objects and see if they are the same

TableIO:Add NE TableIO:Delete

So rather than the property being a static int/char/whatever (and hence a value) the static property is actually an object

Oh. BTW - *bang* (I hate includes)

 * jmls goes off to write a enum class generator

Posted by Peter Judge on 11-Jan-2011 07:21

Right. So you are saying that each enum is an object, with a value and a

label. This means that you can compare objects and see if they are the same

TableIO:Add NE TableIO:Delete

So rather than the property being a static int/char/whatever (and hence a

value) the static property is actually an object

Indeedy. The main benefit of this is, to me, not that you can compare them in any better/worse/different way: after all, TableIO:Add NE TableIO:Delete will return true regardless of the type of the enum. The main benefit to me is that you can say

Method public void DoTableIOAction(input poTableIOAction as TableIO) <

Posted by jmls on 17-Jan-2011 14:09

So, am I right that using enums as classes instead of "constants" is that

IF PhoneLine.LineType EQ enum.PhoneType:Landline

becomes

IF enum.PhoneType:enum(PhoneLine.LineType) EQ enum.PhoneType:Landline

(where :enum is a static method in the enum.PhoneType class that returns the appropriate enum class of PhoneType )

Posted by Admin on 17-Jan-2011 14:21

IF enum.PhoneType:enum(PhoneLine.LineType) EQ enum.PhoneType:Landline

(where :enum is a static method in the enum.PhoneType class that returns the appropriate enum class of PhoneType )

A bit too much enum in your namings for my taste but in principle to looks like what I'd do. I'd however name that method FromString or FromValue - but I'm know to be .NET influenced

Consider organizing the code in a name space, when mixing your cod with others is should not become impossible.

Posted by Peter Judge on 17-Jan-2011 14:22

jmls wrote:

So, am I right that using enums as classes instead of "constants" is that


IF PhoneLine.LineType EQ enum.PhoneType:Landline




becomes





IF enum.PhoneType:enum(PhoneLine.LineType) EQ enum.PhoneType:Landline




(where :enum is a static method in the enum.PhoneType class that returns the appropriate enum class of PhoneType )


Yes. Or rather, that's exactly what I do. I suspect that you'll have to do this infrequently, since from that point on, all you'll use in your code is the enum class value, and not the DB field value.

-- peter

Posted by Admin on 17-Jan-2011 14:31

Yes. Or rather, that's exactly what I do. I suspect that you'll have to do this infrequently, since from that point on, all you'll use in your code is the enum class value, and not the DB field value.

Typically not in the new form of the business logic. Typically at the data access layer and the service interface, eventually at the client, when deserializing whatever came from the backend.

Posted by Peter Judge on 17-Jan-2011 14:40

mikefe wrote:

Typically not in the new form of the business logic. Typically at the data access layer and the service interface, eventually at the client, when deserializing whatever came from the backend.

Just to pick a nit, but the value you'll de- and serialize in the service interface is the enum's value which can be something completely different from the value in the DB. It's easier to keep 'em the same but just wanted to point out that techically the only place you'll work with the DB value is the data access layer.

(I did say it was nit-picky)

-- peter

Posted by Admin on 17-Jan-2011 14:51

Just to pick a nit, but the value you'll de- and serialize in the service interface is the enum's value which can be something completely different from the value in the DB. It's easier to keep 'em the same but just wanted to point out that techically the only place you'll work with the DB value is the data access layer.

Indeed. And the serialization to/from the DB and to/from the SI might return different data types as well. My preference for a string serialization is ToString() and deserialization is FromString(). That's helpful for log files and test messages as well.

This thread is closed