What is a Function()?

First of all, this is a very basic explanation of the topic, what a FUNCTION() is. And a very lengthy one. So, in case you already know that, it will be boring. Move on, nothing to see here for you. ;-)

Simply and in general said, a FUNCTION is some independent code, that can be called called from other parts of your program. The important part here is independent!
This means, you do NOT refer to any variable outside this code from inside your FUNCTION! Global variables are not meant for such!
As so often, there is an exception on this. More about that in another example some time later.

Move your mouse here, over this text, to see, why this is important....

Thanks to the unknown author of this meme!
It is so on point, I had to steal it.

A FUNCTION in Clarion is the same as a SOURCE PROCEDURE. The difference between them is, that you send something to that procedure (in some cases) and you get get something back (in some cases). The values you send to this function are called PARAMETERs. And the result you get back in return, well, lets call it result.
Each function will look like FUNCTION( Parameter1, Parameter2, ....., ParameterN) - depending on how you have defined it.
However, there will be an important restriction we have to keep in mind. While we can send several different parameters to such a function, we will receive back only one value. Not three, not two, just one!
More on that later.

We will tinker a FUNCTION now, which will sum up two values we pass a parameters and we get back the sum of these two numbers.
it looks like this:

SUM(LONG pNumber1, LONG pNumber2) which will give us the sum of these two numbers.

Inserting a new PROCEDURE from the ABC Application Builder Templates will look like this:

I declared it globally, so I can call this function at any time from any other procedure.

And this is how this code will look inside, when opening the Source Embeditor:

!!! Generated from procedure template - Source 

SUM        PROCEDURE  (LONG pNumber1,LONG pNumber2) ! Declare Procedure
! Start of "Data Section"
! [Priority 1300]
LOC:nReturnValue               LONG
! End of "Data Section"
! Start of "Local Data After Object Declarations"
! [Priority 5000]
! End of "Local Data After Object Declarations"

! Start of "Processed Code"
! [Priority 5000]
        LOC:nReturnValue = pNumber1 + pNumber2
! End of "Processed Code"
! Start of "Procedure Routines"
! [Priority 3500]
! End of "Procedure Routines"
! Start of "Local Procedures"
! [Priority 5000]
! End of "Local Procedures"
For all non-Clarionites, the code with the grey background was automatically generated by Clarion. We can write our own code into the white gaps. This Application Generator is a big plus of Clarion. It is a powerful tool. Well, not in this example, but when it comes to real life applications, it helps you to accelerate your work tremendously!

We now have three interesting part in this snippet.
The first one is
SUM     PROCEDURE (LONG pNumber1,LONG pNumber2) ! Declare Procedure
which is called the PROTOTYPE. It describes this function. It contains its name and what we hand over to the code.

The next point of interest is the declaration of a variable,
LOC:nReturnValue   LONG.
In Clarion the labels of procedures, objects and variables etc. are placed in the very first column. The Embeditor then displays those labels in red. All other code, which is meant to execute, MUST NOT be written in the very first column!
That specific place is reservered for labels. The compiler needs this as a differentiator.

And finally the code itself.

        nReturnValue = pNumber1 + pNumber2

Lets say, the function somewhere in the program got written like this:

VAR:nSomeCalculation = SUM(3, 5)

then inside our function SUM() we have the first parameter, pNumber1, filled with 3 and the second, pNumber2, filled with 5. The new function SUM() will then return the value of 8, which then gets assigned to VAR:nSomeCalculation.
It is a good habit to give sounding names to variables. In this case, the leading p let us know, that we deal with a parameter. So pNumber1 is the is the first of several numeric parameters. If we would define a local variable inside our function, like LOC:Number1, we can easily tell the variable from the parameter pNumber1.

Now to the question, why there is a variable to be used for RETURN() at all? Why not simply RETURN(pNumber1+pNumber2) instead? It would save us 50% of code!

Well, yes, it would. But imagine some more sophisticated code, with a tad more number of lines. It is another good habit to have only one place, where the RETURN() is called. The call to RETURN() will end your code and leaves the function. If you have several different locations in your function to call a RETURN() and leave, then this is an invitation for bugs. Because you leave the function, before the code probebly has been worked through.
You do not want that!
One more reason to keep functions small and simple. But code tends to grow and sometimes it becomes a blind bend and confusing, even with the best intent. Speaking of habits, its always good to assign a ReturnValue with something meaningful. In case non of you IF-conditions worked in you code, it would not be a good idea to return your ReturnValue in a non-defined state.
If you expect some positve numeric value from your code, you might pre-assign your ReturnValue with some negative value.
Like -1 or maybe -999, which makes absolutely sure that something went wrong.

See also "RETURN (return to caller)" in the Clarion Help (press the F1-key).

And speaking of habits, finally another programming tip, provided by Mike Hanson of BoxSoft. If you have a bunch of determinations to do, you sometimes might end up like this:

IF some_condition THEN
       DO This
       IF some_other_condition THEN
               DO That
               IF some_third_condition THEN
                       DO Something
                       IF still_not_happy THEN
                               DO Gasp

This looks really sort of hodgepodge, eh?

Mikes suggestion was as simple as this: Embrace the conditions with 1 LOOP and exit it with a BREAK, if the condition is suitable.
If the first condition is not met, the second is tried. Then probably the third one.

   IF some_condition       THEN DO This      ; BREAK .
   IF some_other_condition THEN DO That      ; BREAK .
   IF some_third_condition THEN DO Something ; BREAK .
   IF still_not_happy      THEN DO Gasp      ; BREAK .

You need to sort your conditions inside this LOOP in a thoughtful manner, of course. But you guessed that. Right?
But it looks much cleaner! And cleaner means safer!

NOTE: the period . has the same meaning as END. Makes a line of code quite readable.
The semicolon inside a line of code advises the compiler to treat the following command like being on a separate line on its own.

At the top of this text I claimed, that you can send several parameters to a function, but you get back only one single value.

Well, normally each defined parameter has to be filled. And you as the programmer are responsible that the contents of the received parameters is correct. If you expect a numeric value, but get a character - what will you do to catch this mismatch? You better plan ahead before you wreak havoc. Even more, you may design for a parameter to be optional.

And even better, you can get back more than just one single value.

More on that later..... just ask.

Thats mostly all! Add salt and pepper as you like....

Page uploaded: 27. March 2023

Here you find some more samples