Clarion Quiz: why is it than you can also use the following code RECORDS(Collection)

Originally posted by @MarkGoldberg on Skype, I think this is an interesting topic and worth repeating and discussing in more detail!


…one interesting thing about coding classes for queue’s Is you write things a few different ways.

CwUnit/Libsrc/ctQueue.clw at master · MarkGoldberg/CwUnit · GitHub Has this method: (debugging removed below):

ctQueue.Records PROCEDURE()!,LONG
   CODE
   RETURN RECORDS( SELF.BaseQ )

Then when Collection is a class you can write any of these:

            Collection.Records()     
   RECORDS( Collection.Q )
   RECORDS( Collection.BaseQ )

Clarion Quiz: why is it than you can also use the following code ?

   RECORDS( Collection )  
1 Like

…and for my response!

This is explained in the “Method Definition” section of the CLASS help topic.

###Method Definition

Remember that on the PROCEDURE definition statement you are assigning labels for use within the method to all the passed parameters, and so, since the CLASS’s label is the data type of the implicit first parameter, you must use SELF as the assigned label for the CLASS name parameter. For example, for the following CLASS declaration:

MyClass CLASS

MyProc   PROCEDURE(LONG PassedVar)             !The method takes 1 parameter
        END

you may define the MyProc PROCEDURE either as:

MyClass.MyProc PROCEDURE(LONG PassedVar)       !Prepend the CLASS name to the method's label
 CODE

or as:

MyProc PROCEDURE(MyClass SELF, LONG PassedVar) !The CLASS name is the implicit first parameter's data type, labeled SELF
 CODE

The following lines of code are identical from the compilers point of view:

MyClass.MyMethod( Arg1, Arg2 )  

MyMethod(MyClass, Arg1, Arg2 )

The compiler really sees it as the 2nd form.
You will see that in errors about for a missing procedures (err method)
You will see that in The name mangling in a .EXP (for exporting from a DLL)

1 Like

I can see RECORDS( Collection.BaseQ ) work, but I’m not sure what

Collection.Records()
RECORDS( Collection.Q )

would return?

One thing to remember because of the implied first parameter being SELF, that if you use OMITTED(ParamNumber) that it needs to start at 2 not 1! So if you have

MyMethod PROCEDURE( pS, pX)

you need to refer to pS as 2 and pX as 3 when using OMITTED(). Best is to use the parameter name, as in OMITTED(pS) and OMITTED(pX)

Best regards,
Arnor

1 Like

Hi Arnor consider this code:

!See the following for ctQueue(inc & clw) https://github.com/MarkGoldberg/CwUnit/tree/master/Libsrc


below is ctYada.inc

 INCLUDE('ctQueue.inc'),ONCE

gtYada    GROUP,TYPE
ID           LONG
Description &STRING
          END

qtYada    QUEUE(gtYada),TYPE
          END

ctYada    CLASS(ctQueue),TYPE,MODULE('ctYada.clw'),LINK('ctYada.clw')
Q            &qtYada
CONSTRUCT    PROCEDURE
DEL          PROCEDURE(),DERIVED
Add          PROCEDURE(LONG xID, STRING xDescription)
          END

below is ctYada.clw

   MEMBER()
   INCLUDE('ctYada.inc'),ONCE
   MAP
   END

ctYada.Construct PROCEDURE
   CODE
   SELF.Q     &= NEW qtYada
   SELF.BaseQ &= SELF.Q
   CLEAR(SELF.Q)

ctYada.Del PROCEDURE
   CODE
   DISPOSE(SELF.Q.Description)
   PARENT.Del()

ctYada.Add PROCEDURE(LONG xID, STRING xDescription)
   CODE
   SELF.Q.Description &= NEW STRING( SIZE(xDescription) ) 
   SELF.Q.Description  =                  xDescription
   SELF.Q.ID           = xID
   ADD(SELF.Q)        

Then elsewhere

     INCLUDE('ctYada.inc'),ONCE
Collection    ctYada
     CODE
     Collection.Add(42,'So')
     Collection.Add(43,'Long,')
     Collection.Add(44,' And ')
     Collection.Add(45,'Thanks for' )
     Collection.Add(46,' all the Fish' )

     MESSAGE('Collection has ['& Collection.Records()       &'] Rows' & |  Method call   
            '|Collection has ['& RECORDS(Collection.Q)      &'] Rows' & |  RTL call
            '|Collection has ['& RECORDS(Collection.BaseQ)  &'] Rows' & |  RTL call
            '|Collection has ['& RECORDS(Collection)        &'] Rows' & |  Method Call
            '',|
            'A Few ways to show the same thing')

As a side note, when Collection leaves scope it’s destruct will be called
The ctQueue.Destruct() calls SELF.Free() which calls SELF.Del() for each row
DEL as you can see is derived in ctYada to dispose of the description reference
So this queue will automatically dispose of all of the references in the queue as it leaves scope

Hi Mark,

Didn’t see the Records method, but why does RECORDS(Collection) return anything meaningful? You are calling it on a class instance, not a queue? What happens if you have multiple queues in the class?

Best regards,
Arnor,

@ArnorBld

Consider this class:

Collection       CLASS()
Records            PROCEDURE() ,LONG
  END

Collection.Records PROCEDURE() !,LONG
  CODE
  RETURN 42

Now you can also define the Records method like this instead of the above:

Records PROCEDURE(Collection SELF) !,LONG
  CODE
  RETURN 42

The implication being that you can turn this around when it comes time to using the class method.

So instead of:

  recordCount = Collection.Records()

You can also do this:

  recordCount = Records(Collection)

Since none of the signatures of Records found in BUILTINS.CLW conflict with your one the compiler knows which one to call.

... from BUILTINS.CLW ...
RECORDS(FILE),LONG,NAME('Cla$FILE_RECORDSf')
RECORDS(KEY),LONG,NAME('Cla$FILE_RECORDSk')
RECORDS(QUEUE),LONG,NAME('Cla$RECORDSqueue')

Note: the above also assumes that I know the heck what I am going on about. Did I get any of that right @MarkGoldberg ?

@brahn,

Hmm… That does not seem to be what Mark is suggesting - from the .inc file:

Records PROCEDURE(),LONG !Returns Records(Q) !an interesting syntax: RECORDS(MyQueueClass) works
Pointer PROCEDURE(),LONG !Returns Pointer(Q) !an interesting syntax: POINTER(MyQueueClass) works

So I’m curious as to how that works. I do not see a RECORDS() procedure in the MAP in the .clw file…

But it’s OK, I’ve never been good at guessing games

Arnor

Its in the class (inc) on line 36:

…and in the clw (not MAP) on line 117:

It doesn’t matter which way you declare it or call it, they are interchangeable.

@brahn,

Interesting. Example:

  PROGRAM
  MAP
  END
MyClass  CLASS
MyMethod   PROCEDURE(),LONG
         END
  CODE
  MESSAGE(MyMethod(MyClass))

MyClass.MyMethod   PROCEDURE()!!,LONG
  CODE
  RETURN(42)

Fairly useless, but interesting :slight_smile:

Best regards,
Arnor

why does RECORDS(Collection) return anything meaningful

Because it’s an alternate syntax to calling Collection.Records()

You are calling it on a class instance, not a queue?

Correct

What happens if you have multiple queues in the class?

Collection itself wraps a single queue
When I have a class that needs multiple queues, I add multiple properties that are classes derived from ctQueue

You did get it right, AND you’ve added another subject to the conversation.
Not only can you call a method using the dot syntax or with the instance as the first argument
but you can also implement the method with either syntax.

@ArnorBld There are two things happening here.

  1. Any method can be called using the “normal” dot syntax OR it can be called with the instance as the first argument

For instance: ThisWindow.Init() can be called as Init(ThisWindow)

  1. We just so happen to have a method name “records” that has an RTL command by the same name.

As @Brahn pointed out, even the RTL command is overloaded with RECORDS([File|Key|Queue])
We’re just adding another overload, in this case RECORDS(ctYada) or ctYada.Records() if you like the normal syntax

Test of “quote reply” system (learning how to have a decent thread here on clarionhub)
To use Quote Reply, Highlight text of a post, and notice a new button that appears above the highlighted text…

1 Like

Hi Mark,

The original sample/question is confusing because you are using a method with the same name as a Clarion statement. Using a different method name would have made this clearer and more meaningful to illustrate this alternate way of calling methods:)

Best regards,
Arnor

But Arnor. isnt that the Whole point of this example?