Multi-line FUNCTIONs

x13

Nov 9, 2016
53
0
Netherlands
Hi all.

Not sure whether this has already been suggested (sorry if it was).

So.
There's IFF-ENDIFF, DO-ENDDO, SWITCH-ENDSWITCH, etc.

Why not have the same with FUNCTION ?
This would be a great feature because defining everything on a single line is often like writing embedded IF()'s in Excel.

Example:

FUNCTION LeapYear[%1]

REM Implicit sub-SETLOCAL within function definition

SET cent=%@INT[%1/100]
SET yr=%@EVAL[%1-%cent*100]

IFF %yr EQ 0 THEN
SET res=%@IF[%cent MOD 4 EQ 0,1,0]
ELSE
SET res=%@IF[%1 MOD 4 EQ 0,1,0]
ENDIFF

REM Function result would be mandatory, obviously!
SET LeapYear=%res
ENDFUNCTION
I'm not eve sure if above code would work on a single-line definition...

just my 2¢
 

x13

Nov 9, 2016
53
0
Netherlands
Well, LIBRARY seems to behave like a DLL (or .obj file that can be linked and re-linked by executables).
Not sure if it's actually the same thing as what I proposed, though you could have a library containing only a single item.

The documentation doesn't give a clear example of how this works.
Has anyone tried this?
 
May 20, 2008
9,553
64
Syracuse, NY, USA
I'm not eve sure if above code would work on a single-line definition...
Well, if one was extremely determined ... word for word ...
Code:
v:\> function LeapYear `%@exec[@set cent=%@int[%1/100]]%@exec[@set yr=%@eval[%1-%cent*100]]%@exec[@iff %yr EQ 0 then & @set res=%@IF[%@eval[%cent MOD 4] EQ 0,1,0] & else & @set res=%@IF[%@eval[%1 MOD 4] EQ 0,1,0] & endiff]%res`

v:\> do yr in /L 1900 1901 1904 2000 2001 2004 ( echo %yr ... %@leapyear[%yr] )
1900 ... 0
1901 ... 0
1904 ... 1
2000 ... 1
2001 ... 0
2004 ... 1
The three @EXEC's turn into empty strings because @SET and @IFF cause the return values of those commands to be discarded. All you get is the %res at the end.

Here's another, without all the words:
Code:
v:\> function isleapyear `%@if[%@eval[%1 MOD 4] NE 0 .or. (%@eval[%1 MOD 100] EQ 0 .and. %@eval[%1 MOD 400] NE 0),0,1]`

v:\> do yr in /L 1900 1901 1904 2000 2001 2004 ( echo %yr ... %@isleapyear[%yr] )
1900 ... 0
1901 ... 0
1904 ... 1
2000 ... 1
2001 ... 0
2004 ... 1
 
Oct 18, 2009
278
10
Functionally, this is similar to GOSUB with parameters and RETURN {value}.

I too would like to see something like FUNCTION ... ENDFUNCTION. (And I'm the person who originally suggested the Library system.)

Problems with the current Library system (which is still evolving) are passing parameters to a library "function" as specific named variables within the function (like Excel VBA) and inability to return values without custom approaches.

The other problem with the Library approach is where a multi-line UDF really doesn't need to be loaded into memory and re-used, e.g., because it's used 3 times in just one program.

Regarding an ENDFUNCTION statement, the rest of the line should be ignored. For instance, I routinely end my GOSUBs with:

RETURN
:: End of MAIN_RECORDS_PARSE_LOOP

so I can easily tell which routine just ended. ENDFUNCTION (and ENDPROC for languages that use PROC) make the code more readable, especially when a routine has more than one RETURN statement, e.g.

ENDPROC MAIN_RECORDS_PARSE_LOOP
 

x13

Nov 9, 2016
53
0
Netherlands
@Rick:

You took the words right out of my mouth.
While LIBRARY is a neat trick to share BTMs as a "unit" (Turbo Pascal also has those), they still do not return a result.

That being said, you are correct in that RETURN <status> also works, something that's easily overlooked.

Point is that creating a library may be overkill, when you just want one or a few functions in a BTM, but not necessarily need them in memory permanently.

Anyway.
Maybe ENDFUNCTION will eventually be added in a later build.
Here's hoping...

x13
 
May 20, 2008
9,553
64
Syracuse, NY, USA
Technically, library routines do (can) return a result (in ?, oddly enough).
Code:
g:\tc24\library> library /f test
test {
echo This is a test.
quit 666
}

g:\tc24\library> test
This is a test.

g:\tc24\library> echo %?
666
I like the idea of having functions in libraries and something similar to what Joe Cavalty alluded to in another thread seems quite nice. There would have to be an indication that it was a variable function ... "@" would be good enough. And there'd have to be a way to specify what the function evaluated to ... "SET @function_name=value" is simple enough, so is (borrowing from C) "SET _this=value" ... but I wouldn't want to see it in the environment. Then we might have (dumb example) in a library.
Code:
@PARITY {
iff %@isdigit[%1] NE 1 then
    set @PARITY=NONE
else
    set @PARITY=%@if[%@eval[%1 MOD 2] == 0,EVEN,ODD]
endiff
}

I also like ENDFUNCTION but how would/should it work?  You would still need a SET (as above) or other specialized way of specifying what the multiline thingy expanded to?
 
Oct 18, 2009
278
10
I don't see a need for SET @MyFunction. For instance, you can't do that in Excel VBA.

It would like to see something like SET PageWidth=%@FormWidth["LETTER"]

Code:
FormWidth {FormName

IFF %FormName EQ "INVOICE" THEN
    RETURN 5

ELSEIFF %FormName EQ "LETTER" THEN
    RETURN 8.5

ELSEIFF %FormName EQ "LANDSCAPE" THEN
    RETURN 11

ELSE
    RETURN 8.5

ENDIFF
}
Alternatively:

Code:
FormWidth {
     VAR FormName
     VAR PaperType

IFF %FormName EQ "INVOICE" THEN
    RETURN 5

(etc ...)
Frankly, I like the VAR approach better--more readable. Either way, it would avoid having to use %1, %2, etc.
 
Oct 18, 2009
278
10
I haven't actually used the Library system. My point was I don't see a need for SET @MyFunction.

I think everyone who has been working with the Library system agrees that it needs a standardized way to return values, including string values, and not one using QUIT, which only returns numeric exit codes.