Variable number of parameters

This forum is meant for questions about the Visual FoxPro Language support in X#.

atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

Variable number of parameters

Post 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 ...])
User avatar
Chris
Posts: 4922
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Variable number of parameters

Post 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
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Variable number of parameters

Post 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
User avatar
Chris
Posts: 4922
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Variable number of parameters

Post 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...
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Variable number of parameters

Post 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
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

Variable number of parameters

Post by atlopes »

Thank you both, Chris and Karl-Heinz. I'm experimenting with this and it is working.
leon-ts
Posts: 435
Joined: Fri Feb 03, 2017 1:43 pm

Variable number of parameters

Post 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
Best regards,
Leonid
User avatar
robert
Posts: 4529
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Variable number of parameters

Post 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

Code: Select all

IntPtr.Zero
When I enable /lb+ I see that the translation of NULL_PTR has become

Code: Select all

(long)IntPtr.Zero
I am not sure why that is, but this needs to be fixed.

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
leon-ts
Posts: 435
Joined: Fri Feb 03, 2017 1:43 pm

Variable number of parameters

Post 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
Attachments
ConsoleApplication1.rar
(7.35 KiB) Downloaded 67 times
Best regards,
Leonid
User avatar
robert
Posts: 4529
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Variable number of parameters

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
Post Reply