Page 1 of 2
Variable number of parameters
Posted: Mon May 18, 2020 8:44 pm
by atlopes
Sorry for what will likely be a very basic question, but in X# how can a function declaration specify an unknown, variable number of parameters?
Something that could allow the implementation of the MIN() VFP function as close as possible to:
Code: Select all
MIN(eExpression1, eExpression2 [, eExpression3 ...])
Variable number of parameters
Posted: Mon May 18, 2020 9:13 pm
by Chris
António,
There are two different ways. For untyped functions, you can use the PCount() / _GetFParam() pairs of intrinsic functions, to retrieve amount of parameters passed and each of them:
Code: Select all
FUNCTION UntypedFunc() CLIPPER
FOR LOCAL n := 1 AS INT UPTO pcount()
? "Parameter" , n , "=" , _GetFParam(n)
NEXT
RETURN NIL
For strongly typed functions/methods, you can use the same mechanism that c# uses as well, with the params keyword (ParamArray attribute in X#):
Code: Select all
FUNCTION TypedFunc([ParamArray] aParams AS OBJECT[]) AS VOID STRICT
FOR LOCAL n := 1 AS INT UPTO aParams:Length
? "Parameter" , n , "=" , aParams[n]
NEXT
Variable number of parameters
Posted: Tue May 19, 2020 7:37 am
by Karl-Heinz
Hi Chris,
When i compile your TypedFunc() i get the warning:
warning XS0674: Do not use 'System.ParamArrayAttribute'. Use the 'params' keyword instead.
Finally i found out how to use the PARAMS keyword:
Code: Select all
LOCAL c := "Wall" AS STRING
?
TypedFunc ( 1 , TRUE , , c )
?
TypedFunc ()
// FUNCTION TypedFunc([ParamArray] aParams AS OBJECT[]) AS VOID STRICT
FUNCTION TypedFunc( aParams PARAMS OBJECT[] ) AS VOID STRICT
? "Param count:" , aParams:Length
FOREACH VAR a IN aParams
? ValType ( a ) , a , IsNil ( a ) // ok
NEXT
RETURN
Isn´t it possible to pass a var by ref ? I tried "@c" and "REF c" but that doesn´t work.
regards
Karl-Heinz
Variable number of parameters
Posted: Tue May 19, 2020 7:48 am
by Chris
Hi Karl-Heinz,
Ah, right I keep forgetting that it is possible to also use the PARAMS keyword!
No, you can't pass params by reference like that, after all there's not a parameter variable name in the receiving function to assign back a new value to it. You could say you could put back the value to the array element, but if you want to do this, you can pass an array to a regular function in the first place...
Variable number of parameters
Posted: Tue May 19, 2020 7:55 am
by Karl-Heinz
Chris wrote:Hi Karl-Heinz,
No, you can't pass params by reference like that...
thanks, already thought that this would not work.
regards
Karl-Heinz
Variable number of parameters
Posted: Tue May 19, 2020 11:41 am
by atlopes
Thank you both, Chris and Karl-Heinz. I'm experimenting with this and it is working.
Variable number of parameters
Posted: Wed May 20, 2020 11:54 am
by leon-ts
Hi to all!
Is there any way to save information about parameter types when calling functions with a variable number of parameters?
For example, there is a function:
Code: Select all
FUNCTION MyTestFunc(a PARAMS OBJECT[]) AS VOID
? a[1]:GetType():FullName
? a[2]:GetType():FullName
? a[3]:GetType():FullName
? a[4]:GetType():FullName
RETURN
All options in the project properties in the "Language" and "Dialect" sections (except for Unsafe code) are disabled (FALSE).
Call:
Code: Select all
MyTestFunc( NULL_PTR, "abc", (DWORD)1, NULL_STRING )
Result:
a[1]: System.IntPtr, OBJECT {PTR}
a[2]: System.String, OBJECT {STRING}
a[3]: System.UInt32, OBJECT {DWORD}
a[4]: null, OBJECT // exception
Type information lost for a[4]
Enable the "Allow late binding" property in TRUE.
Call function (previous example)
Result:
a[1]: null, OBJECT // exception
a[2]: System.String, OBJECT {STRING}
a[3]: System.UInt32, OBJECT {DWORD}
a[4]: null, OBJECT // exception
Type information lost for a[1] and a[4]
Best regards,
Leonid
Variable number of parameters
Posted: Wed May 20, 2020 2:42 pm
by robert
Leonid,
The /vo2 compiler setting determines how NULL_STRING is interpreted.
With /vo2+ it will replace NULL_STRING with String.Empty. In that case the 4th parameter will have the right type.
When I run your code with only /vo2+ I see the following result
Code: Select all
System.IntPtr
System.String
System.UInt32
System.String
I fyou look at the code with ILSpy you will see that the NULL_PTR is translated to
When I enable /lb+ I see that the translation of NULL_PTR has become
I am not sure why that is, but this needs to be fixed.
Robert
Variable number of parameters
Posted: Wed May 20, 2020 6:10 pm
by leon-ts
Robert,
I turned on /vo2+ and I managed to save the string type. This is what I need. But PTR is still a problem. It comes into function as NULL.
I modified the example a bit as follows.
Code: Select all
FUNCTION MyTestFunc(p AS PTR, a PARAMS OBJECT[]) AS VOID
RETURN
And Call:
Code: Select all
MyTestFunc( NULL_PTR, NULL_PTR, "abc", (DWORD)1, NULL_STRING )
The parameter 'p' takes the type System.Void *. And this is exactly the type that I expect. In particular, I expect this from type a[1], because NULL_PTR is also passed to it, but this does not happen. It contains NULL. (at /lb+ and at /lb-)
When I create a library (.dll) in XSharp and place a function in it, where one or several parameters are described as AS PTR, then if you look at its MethodInfo, it shows this parameter as type System.Void * (not System.IntPtr). If the function has overloads, then in order to correctly extract the necessary overload using the Type.GetMethod() method, I need to pass in it an array of exact parameter types of the desired function. And if you pass System.IntPtr to the example I gave, instead of System.Void *, then Type.GetMethod() will return null (not found).
P.S. I am developing a generic function to call other functions from dynamically loaded assemblies. AssemblyName, ClassName, FunctionName and parameters of the called function (variable length, via PARAMS) are passed to this general function. And for this it is very important to extract valid types from PARAMS.
P.S.2. The problematic example is in the attachment.
Best regards,
Leonid
Variable number of parameters
Posted: Thu May 21, 2020 8:39 am
by robert
Leonid,
I already confirmed that there is a problem with NULL_PTR being passed incorrectly to a function that takes a PARAMS OBJECT[] yesterday when /lb+ is enabled.
I am already working on this.
Robert