PDA

View Full Version : unlimited function-parameters?



ReneMiner
21-10-2014, 14:24
is it possible in thinBasic to call a function with a dynamic count of function-parameters?
( all of the same, fixed-size type ).:confused:

Somewhat like MKL$( param1[, param2[, param3,...]] ) ?

or is the only way to pass a list (string) made up like MKL$, MKBYT$, MKDWD$, Memory_Get for UDt etc. and to place some layover there to read it out. But i don't want to create a string as first to pass the list of parameters to the function...

short example what i mean:



' i want to pass maybe 3, but maybe 33 or 333 longs, so have to do it alike

myFunc( MKL$(123, 234, 345) )
' or
myFunc( MKL$(123, 234, 345, 456, 567, 678,...) )

Function myFunc( Byval sLongs As String )

Local lLong(StrPtrlen(StrPtr(sLongs))/4) As Long At Strptr(sLongs)

' now the function has a list of long values available
' UBound(lLong) tells how many

End Function



and i want to do it without the MKL$, so to say- instant array alike



myFunc( 123, 234, 345 )

myFunc( 123, 234, 345, 456, 567, 678,... )

Function myFunc( ByVal lLong() As Long )

End Function


no doubt: this "ByVal lLong()" has to be the only - or last passed parameter.
None may follow.

Else it would need a syntax like on array-assignement using brackets here
(which i don't like)


myFunc( [123, 234, 345, 456, 567, 678,...] )' including [] brackets passed


In the other direction would be very interesting if one could automatically create a list from a function-result like this:



Function myFunc(Byval parameters As whatever) AS STRING

Local lResult(123) As Long

Function = Memory_Get( Varptr(lResult(1)), SizeOf(lResult) )

'EDIT: ' cool would be "Function = Array All lResult" instead

End Function


'------------------------------------------------
Dim lLong() AS LONG = myFunc(somedata)

' when assigning a STRING (on dimensioning) to something with
' empty parenthesis that is NOT a STRING it could instantly create fitting array...

Redim lLong() = myFunc( someOtherData ) '...




not far from returning dynamic arrays as function-result -
but the intention is indeed that i want to pass a list of same-type-parameters where nobody knows in advance how many. :D

ErosOlmi
21-10-2014, 18:18
Here an example of optional parameters passing but I doubt it can satisfy your request:




MsgBox 0, "Sum of passed parameters: " & MySum(1,2,3) & $CRLF + "(9th and 10th parameter are predefined to be 100 and 1000)"


Function MySum(
N01 As Ext ,
Optional '---From here all parameters will be considered optional
N02 As Ext ,
N03 As Ext ,
N04 As Ext ,
N05 As Ext ,
N06 As Ext ,
N07 As Ext ,
N08 As Ext ,
N09 As Long = 100 , '---Default value
N10 As Long = 1000 '---Default value
) As Ext



Function = N01 +
N02 +
N03 +
N04 + N05 + N06 + N07 + N08 + N09 + N10

MsgBox 0, "We are inside function: " & Function_Name & $CRLF &
"Function has been declared to have " & Function_NParams & " parameters." & $CRLF &
"Function has been called with " & Function_CParams & " parameters."

End Function

Consider ThinBasic function parameters are limited to 32

What you need is some sort of variadic function, a function that can accepts an undefined number of parameters you can define at run time.
ThinBASIC has no way to define a variadic function, unless you create a compiled module and create your own function parsing an infinite number of parameters.
For example the following is MKL$() function developed into a module (in this case thnCore main engine module) using Power Basic (but can be easily developed using FreeBasic or other compiled languages using thinBasic SDK)

'------------------------------------------------------------------------------
Function Exec_MKL() As String
'------------------------------------------------------------------------------
'Syntax: s = MKL$(Number [, ...])
'------------------------------------------------------------------------------
Local eNumber As Ext
Local pp As Long
Local sTemp As String

pp = thinBasic_CheckOpenParens_Optional
Do
thinBasic_ParseNumber eNumber
sTemp = sTemp & Mkl$(eNumber)
Loop While thinBasic_CheckComma_Optional

If pp Then thinBasic_CheckCloseParens_Mandatory
Function = sTemp


End Function

As you can see an infinite number of numeric expressions can be parsed by ThinBASIC engine until it will encounter a comma.

I think the best option you have now is using your first example:

myFunc( MKL$(123, 234, 345) )
' or
myFunc( MKL$(123, 234, 345, 456, 567, 678) )

Function myFunc( Byval sLongs As String )

Local lLong(StrPtrlen(StrPtr(sLongs))/4) As Long At Strptr(sLongs)

' now the function has a list of long values available
' UBound(lLong) tells how many

End Function

mike lobanovsky
22-10-2014, 01:28
AFAIK modern Oxygen supports two notations for variadic functions with unlimited number of arguments:

function foo(...)

and

function foo(sys n, ...)

wherein access to the variadic args is provided through the internal array called param[].

The former one looks more formal and suitable in case the first argument would supply some additional information on the other arguments actually passed or when such information is known to the function from some other, e.g. global, sources. The latter one seems more handy when one needs to iterate somehow through all the arguments actually passed, in which case n should be the count of elements in param[] since Oxygen does not support the concept of an array's UBound.

For example:

sub f(n, ...)
indexbase 0
' n is in fact param[0]
for x = 1 to n


print param[x]


next

end sub

Perhaps this new feature and the O2-to-TB interface can help the user bypass the existing limitation.

ErosOlmi
22-10-2014, 12:33
Not just round the corner but I had an inspiration and I would like to fix some ideas for future thinBasic feature.

What about something like that: No variadic functions but variadic parameters.

Variadic parameters are defined as standard arrays passed BYVAL ad indicating 3 points between round parentheses.
Example of a function having 2 standard parameters and 2 variadic parameters:

Function MyVariadic(ByVal Whatever As Long, ByVal FirstVariadicParam(...) As Ext, ByVal SecondVariadicParam(...) As String, ByVal x as Long) As Long
'...any code
'...FirstVariadicParam and SecondVariadicParam will be just like LOCAL arrays already filled with values
End Function
FirstVariadicParam and SecondVariadicParam will be just like LOCAL arrays already filled with values and on which programmer will be able to operate like any other local array.



Calling such a function will be like calling a standard functions but passing variadic parameters MUST be enclosed into round parentheses.
Example using above function:

MyVariadic(123, (32.8, val("123"), 100), ("ABC", "ZZZ", STR$(Sin(0.4)) ), 456 )


What do you think? Tell me that you like and sooner or later I will do it! :)

ReneMiner
22-10-2014, 12:58
that "variadic"-expression is driving me nuts in the meantime and sounds like the "heuristic" known from virus-scanners...

i don't care how it's called- it enables us to pass an array or a list of values without having to create local variables in advance to pass them to a function neither do we have to perform half a dozen type-casts? cool.

If it would work into the other direction too were fantastic... like




local myVariablabala(...) Like sType = myFunction()



but why the dots? wouldn't just empty parents [or brackets] serve?

or

myNum(%) - numeric list
myText($) - string list

ErosOlmi
22-10-2014, 13:08
I need the dots into function declaration to understand that a parameter is variadic.
I need round parentheses to surround elements passed to variadic parameter when calling the function because I need to distinguish between normal parameter sequence and elements of a variadic parameter.

Working the other way round ... is something completely different.
On step after another.

ReneMiner
22-10-2014, 13:20
just for interest, would it also be possible to pass an array at once to fill a variadic function-parameter?

like


Function myFunc( Byval passedItems(...) As Long )
'...
End Function

Dim myArray(123) As Long

myFunc( ( Array All myArray ) )

' that syntax does not exist but the keywords do...

ErosOlmi
22-10-2014, 18:46
Yes it can be done.
It would be contrary to your request not to have to declare a variable but can be done.

First I need to develop the main functionality.
If the base idea is there, a lot of options can be added later.

ReneMiner
22-10-2014, 20:30
...
It would be contrary to your request not to have to declare a variable but can be done....


why? i do as usual some virtual layover onto some array@heap :D
- that data exists already so no allocation-time

ErosOlmi
22-10-2014, 22:42
OK, I could not resist ! :D
I think I've already developed VARIADIC function parameters ... so far ONLY FOR NUMERIC parameters.

Attached a new test thinCore.dll (thinBasic Core Engine).
To test it extract and copy thinCore.dll into \thinBasic\ directory replacing your current one.
BE SURE TO HAVE thinBasic 1.9.14 (http://www.thinbasic.com/community/showthread.php?12478) already installed.

I HAD TO abandon the idea to use ... (ellipsis) to indicate variadic parameters and use (ANY) clause. If someone has a better idea, I'm open to try to change this.

See example below:


Uses "Console"


Function Variadic1(FirstVariadicParam(Any) As Ext, sBuffer As String) As Long
PrintL "From inside " & Function_Name
PrintL "Variadic parameter 'FirstVariadicParam' number of elements:", UBound(FirstVariadicParam)
PrintL "----------------------------------------------------------------------------"


PrintL "Listing all values:"
For lCount As Long = 1 To UBound(FirstVariadicParam)
PrintL " - Element", lCount, "has value of", FirstVariadicParam(lCount)
Next
PrintL

Function = UBound(FirstVariadicParam)


End Function


Randomize Timer
'---Because first parameter is variadic, pass any number of numeric expressions in surrounding round brackets
PrintL "Function exit value", Variadic1((123, 456, 789, Sin(Rnd), Cos(Rnd)), "ABCDE")


WaitKey


Next days I will go on adding variadic parameter functionality also to other data types: strings, variants, possibly UDT

Ciao
Eros

ReneMiner
22-10-2014, 22:47
È incredibile!

Why not "Array" instead of "Any" - it's one...

Charles Pegge
22-10-2014, 23:23
Without a formal UBOUND, The easiest way for Oxygen to emulate this mode of param passing would be:

function fun(double*d, sys n)
sys i
for i=1 to n
' d[i] ...
next
end function


double d={1,2,3,4,5,.6,.7,.8}
fun d, countof d

ReneMiner
22-10-2014, 23:32
i'm trying but trying to call a type-function always Errors, unbalanced parentheses, my test won't run :(


Uses "Console"

Type t_Test
X As Long
fun As Function

End Type

Function t_Test.fun(ByVal l(Any) As Long)

End Function

Dim x As t_test

x.fun((1,2,3))


WaitKey

ErosOlmi
22-10-2014, 23:37
Sorry Rene but so far it is only for standard functions.
Give me few days and I will extend much more.

ErosOlmi
22-10-2014, 23:46
Sorry again Rene, it was just a matter of ... minutes :D
Attached a new thinCore.dll

Here a working example:


Uses "Console"


Function Variadic1(FirstVariadicParam(Any) As Ext, sBuffer As String) As Long
PrintL "From inside " & Function_Name
PrintL "Variadic parameter 'FirstVariadicParam' number of elements:", UBound(FirstVariadicParam)
PrintL "----------------------------------------------------------------------------"


PrintL "Listing all values:"
For lCount As Long = 1 To UBound(FirstVariadicParam)
PrintL " - Element", lCount, "has value of", FirstVariadicParam(lCount)
Next
PrintL

Function = UBound(FirstVariadicParam)


End Function


Type t_Test
X As Long
fun As Function
End Type

Function t_Test.fun(ByVal l(Any) As Long)
PrintL "From inside " & Function_Name
PrintL "Variadic parameter 'FirstVariadicParam' number of elements:", UBound(l)
PrintL "----------------------------------------------------------------------------"


PrintL "Listing all values:"
For lCount As Long = 1 To UBound(l)
PrintL " - Element", lCount, "has value of", l(lCount)
Next
PrintL

Function = UBound(l)

End Function

Dim x As t_test

x.fun((1,2,3))



Randomize Timer
'---Because first parameter is variadic, pass any number of numeric expressions in surrounding round brackets
PrintL "Function exit value", Variadic1((123, 456, 789, Sin(Rnd), Cos(Rnd)), "ABCDE")


WaitKey




I'm going to bed now: today I just did 14 working hours, I'm really tired :sick32:

ReneMiner
23-10-2014, 00:05
OK, thanks once more. Sleep well.


Perhaps you can look over the array-scan - theres still some problem with continous scan- returns wrong numbers

http://www.thinbasic.com/community/showthread.php?12459-ARRAY-ideas&p=91572#post91572
(http://www.thinbasic.com/community/showthread.php?12459-ARRAY-ideas&p=91572#post91572)
and have a look into support-section too please.


Now this my unlimited multidimensional layover-example upon some array at heap (fits the tB-structure up to 3 dimensions if 1-based), needs the units below and the thincore from above.


Uses "console"
' needs 1.9.14 + latest thincore.dll

#INCLUDE "Heap_Array.tBasicU"


Function TBMain()


Local harry As Heap_Array

Local Bounds(3) As Dimensions

' want 3 dimensional grid of pointers, 1-based

Bounds(1).LoBound = 1 : Bounds(1).HiBound = 2
Bounds(2).LoBound = 1 : Bounds(2).HiBound = 4
Bounds(3).LoBound = 1 : Bounds(3).HiBound = 6

' call to allocate and set up the dimensions at once
harry.PtrsAlloc( harry.BoundsBe( Memory_Get(VarPtr(Bounds(1)), SizeOf(Bounds)) ))

' place a
Local lPtr As DWord At harry.ElementPtr(( 1,2,3 ))

' load the lPtr with data
lPtr = HEAP_AllocByStr("i test 1,2,3")

SetAt( lPtr, harry.ElementPtr(( 2,1,5 )) )
lPtr = HEAP_AllocByStr("i test 2,1,5")

SetAt( lPtr, harry.ElementPtr(( 2,4,6 )) )
lPtr = HEAP_AllocByStr("i test 2,4,6")

' now place standarc-tb-array upon

Local test(2,4,6) Like harry.Layover() At harry.DataPtr

PrintL HEAP_Get(test(1,2,3))
PrintL HEAP_Get(test(2,1,5))
PrintL HEAP_Get(test(2,4,6))

PrintL $CRLF & "-----------------------key to end"
WaitKey

End Function

Billbo
23-10-2014, 01:22
Eros,

The new thinCore.dll you posted, is it to replace the one
that is in the root of the thinAir sub-directory? I one
there is 1,293,824 bytes. Your new one is only 171,008
bytes.

The reason I ask, is that thinBasic did not install a
thinCore.dll in my thinBasic's root directory as you indicate
on Page-1.

Help,

Bill

ErosOlmi
23-10-2014, 07:25
Hi Bill,

inside \thinBasic\ThinAir\ directory there is a special version of thinCore.dll specifically designed to be used only by thinAir.
Do not touch content of that directory.

To test thinCore.dll attached into this post, replace the one you have into \thinBasic\ directory.

Eros

ReneMiner
23-10-2014, 14:36
Just once more i want to say this is a great feature - really happy that you made this possible Eros.

Still thinking about some similar reverse-operation so a function can pass a variadic result back.

Currently it works alike this
(use is mostly for creating a list of items that meet certain conditions which is just needed once - else i store the list at heap and return the pointer)



Type t_Item
isVisible As Boolean
End Type

Function ListVisibleItems( Byval ItemID(Any) As Long ) As String

Local i As Long
Local sResult As String

For i = 1 to Ubound(ItemID)
If myItem(ItemID(i)).isVisible Then
sResult += MKL$(ItemID(i))
Endif
Next
Function = sResult

End Function

Dim myItem(100) As t_Item
'...assume a few items set visible, a few are not

String sVisible = ListVisibleItems((1,2,3,4,5,6,9,14,22,23,24,31,16))

Local lVisible(StrPtrLen(StrPtr(sVisible))/SizeOf(Long)) As Long At StrPtr(sVisible)

' now lVisible() contains all visible items of the list i passed.



how would that work?


Dim lVisible(Any) As Long = ListVisibleItems((1,2,3,4,7,8,43,55))

ReDim lVisible(Any) = ListVisibleItems((5,6,7,8,22,33,43,44,45,57,58))
' ???
Redim lVisible(Any) = "" ' sets Ubound(0) - would be essential - complicated? :(

Dim myPlaylist(Any) As mp3FileInfo = File_Load("c:\myPlaylist.dat")


i think it's complicated :neutral:...

but perhaps we can live with the current available methods for the meantime and focus on something else then.

Billbo
23-10-2014, 15:49
Eros,

Thank you for the clarification. But, you did not
address the thinCore.dll not installing on my
computer. So;

I renamed my thinBasic directory and re-installed
1.9.14.0. This time it installed. Not only that, but
two other files installed in the thinBasic root
directory: thinBasic.exe and thinBasicc.exe. They
were not in my previous directory(??). How has
my thinBasic been running without them. And,
if it has been running okay, why are they needed?

I hope I am not asking stupid questions. I am 68
and I feel that if I don't ask questions and learn
something everyday, the day is wasted.

Thanks, Again,

Bill