ucDefineFunction

 

See Also: ucDefine, ucDefineOperator

 

Defines a function.

 

ucDefineFunction(Definition [, FunctionAddress [, tHandle]])

 

Parameters

 

Definition

Required.  This string argument should consist of a function name, followed by parenthesis, which optionally enclose one or more arguments, followed optionally by a return type.  If this is a self-contained definition, then you continue with an equal sign, followed by an expression that represents the body of code that is executed when the function is invoked.  If this is a callback function, then instead of an equal sign followed by an expression, you would provide a function address in the next argument (FunctionAddress).

 

Argument parts

            An argument has the following syntax and parts:

                  [ByVal | ByRef | ByHandle | ByExpr] argname [As argtype] [= default] [[,] ...]

 

      ByRef

Optional.  Indicates that the argument is passed by reference, and the value can be modified by your callback routine.

      ByVal

            Optional.  Indicates that the argument is passed by value.

      ByHandle

Optional.  Indicates that the value being passed is the handle of the argument.  Given the handle of an argument, your callback can retrieve its properties.  For instance, if the argument is a variable, the callback can use its handle to determine the variable's data type, name, address in memory, etc...

         ByExpr

Optional.  Indicates that the value received by the callback is a handle to the expression that is being passed.  This allows an expression to be passed without first being evaluated.  Your callback has the option of either not evaluating the expression at all, or evaluating it once, or multiple times.  The callback should receive this argument as a ByVal 32-bit value (such as Dword or Long) regardless of the type of the argument itself.

            argname

                  Required.  This is the name of your argument.

            argtype

Optional.  This can be any of the data types supported by uCalc, including: Single, Double, Long, String, WideString, LPCSTR, etc...  If no type is specified, then the default type is used (extended precision, unless you have changed the default type to something else).

            default

Optional.  Unlike some languages, the word "Optional" is not needed.  An argument is considered optional by virtue of having an equal sign followed by a default value.  Also unlike some languages, the default does not have to be a constant; it can be an expression as well.

            ...

Optional.  Three consecutive dots (...) indicate that the function takes an indefinite number of arguments from that point on.  This is valid only with or as the last argument.  If a named argument is immediately followed by the three dots, without a comma, then the rest of the arguments take on the same data type as the named argument.  Otherwise, the arguments are allowed to be of any data type.  The kinds of callbacks that take variable numbers of arguments are different from ordinary callbacks.  These callbacks receive one 32-bit integer value, which us used with ucParamDbl, ucParamLng, or ucParamStr to retrieve arguments, and ucParamCount to retrieve the number of arguments that were passed, as in Example 6 further down.

 

FunctionAddress

Optional.  If you are defining a callback function, then this argument represents the address of the function in your source code that you want to associate with uCalc.  If your function is named MyFunction, then you would pass CodePtr(MyFunction) in PowerBASIC, AddressOf MyFunction in VB Classic, @MyFunction in Delphi, and simply MyFunction in C++.  VB.NET handles this quite differently.  See the VB.NET issues for more details.

 

tHandle

Optional.  You can supply the handle of a given thread so that the function definition is effective only in that particular thread.  See Thread Handling.

 

Remarks

 

ucDefineFunction returns a 32-bit value representing the handle of the function definition.  You can use this later to release the function definition if necessary.

 

Function definitions can be overloaded.  This means that you can apply several definitions to a same function name.  Each definition must be unique either in terms of a different number of arguments, or arguments of differing data types.  In an expression, the proper definition will be selected depending on the arguments that are passed.

 

If two functions share the same name, but their definitions are not sufficiently unique, the newer definition hides the previous one.  The new definition becomes the visible one for subsequent expressions.  If the newest definition is released, it reverts to the previous definition.

 

Recursive function definitions are supported.

 

Functions definitions can be bootstrapped.  This means that you can add to the definition of an already defined function.  A bootstrapped definition is distinguished from a recursive one by appending "~~ bootstrap" to the definition.

 

You can prevent overloading, bootstrapping, or function hiding, by locking the function with the ucLocked property.

 

If a function is defined with no arguments, you can use the function in an expression without parenthesis.  However, the definition itself must use empty parentheses.

 

A definition can have multiple statements, if you separate them with a semicolon.  The last section should evaluate to a value that matches the data type of the function.  The value of this last section is the one that is returned.

 

Be sure that your callback function is defined using the StdCall convention.  Some compilers do this by default.  For those that don't, you must explicitly use the StdCall directive (or equivalent keyword for your compiler) in the callback definition.

 

Be sure that the data types in your definition (both arguments and return types) match the data types of the callback.  If no data type is specified for an argument or return value, then extended precision (80-bit float) is assumed.

 

VB.NET callbacks are handled quite differently from callbacks in other supported compilers.  See the VB.NET help file topic for more details.

 

 

Example 1:

 

' This example demonstrates various self-contained definitions

' It features various concepts including overloading, an optional

' argument, recursion, and specified data types.

 

ucDefineFunction("f(x) = x^2")

ucDefineFunction("g(x, y=5) = x + y")

ucDefineFunction("Twice(value As Double) As Double = value + value")

ucDefineFunction("Twice(value As String) As String = value + value")

ucDefineFunction("ToLong(value As Long) = value")

ucDefineFunction("ToByte(value) As Byte = value")

ucDefineFunction("Factorial(x) = iif(x>1, x*Factorial(x-1), 1)")

 

Print ucEvalStr("f(5)")            ' returns 25

Print ucEvalStr("g(10)")           ' returns 15

Print ucEvalStr("g(10, 20)")       ' returns 30

Print ucEvalStr("Twice(35)")       ' returns 70

Print ucEvalStr("Twice('Bye ')")   ' returns Bye Bye

Print ucEvalStr("ToLong(123.456)") ' returns 123
Print ucEvalStr("ToByte(-1)")      ' returns 255

Print ucEvalStr("Factorial(5)")    ' returns 120

 

 

Example 2:

 

' This example demonstrates a bootstrapped definition

 

ucDefine("Const: pi = Atan(1)*4")

Print ucEvalStr("Cos(pi)")  ' returns -1

Print ucEvalStr("Cos(180)") ' returns -0.59846...

 

ucDefineFunction("Cos(x) = Cos(x*pi/180) ~~ Bootstrap")

Print ucEvalStr("Cos(pi)")  ' returns  0.99849...

Print ucEvalStr("Cos(180)") ' returns -1

 

 

Example 3:

 

' This example shows how easy it is to define a callback.

 

Function MyEasyCallback(ByVal a As Double, ByRef b As Long, ByVal c As Byte) As Double

   MyEasyCallback = a + b + c

End Function

 

ucDefineFunction "MyEasyCallback(ByVal a As Double, ByRef b As Long, ByVal c As Byte) As Double", AddressOf MyEasyCallback

 

 

Example 4:

 

' Here is another callback example.

' Note: Strings are handled in a wide variety of ways from compiler to compiler.

'       uCalc's WideString is what corresponds to VB's String (unicode) type.

'       For other compilers it might be LPCSTR, or String.  See the uCalc demo

'       files for your compiler for more details.

 

Function MyMsgBox(ByRef Prompt As String, ByVal Buttons As Long, ByRef Title As String) As Long

   MyMsgBox = MsgBox(Prompt, Buttons, Title)

End Function

 

ucDefineFunction "MyMsgBox(ByRef Prompt As WideString, ByVal Buttons As Long = 0, ByRef Title As WideString = 'uCalc') As Long", AddressOf MyMsgBox

 

 

Example 5:

 

' This example demonstrates arguments that are passed using ByExpr.

' MyMsgBox is used in two argumetns.  However, only one message box will be displayed.

 

Function MyIIF(ByVal cond As Long, ByVal TruePart As Long, ByVal FalsePart As Long) As Double

   If cond Then MyIIF = ucEvaluate(TruePart) Else MyIIF = ucEvaluate(FalsePart)

End Function

 

ucDefineFunction "MyIIf(ByVal cond As Long, ByExpr TruePart, ByExpr FalsePart) As Double", AddressOf MyIIF

  

Print ucEvalStr("MyIIF('a' > 'b", MyMsgBox('a is bigger'), MyMsgBox('a is smaller'))

 

 

Example 6:

 

' This example uses a different form of callback.  Only one argument is passed.

' This value is used in ucParamCount() and ucParamDbl() or ucParamStr().

Sub MyAverage(ByVal Expr As Long)

   Dim x As Long, Total As Double

 

   For x = 1 To ucParamCount(Expr)

      Total = Total + ucParamDbl(Expr, x)

   Next

 

   ucReturnDbl Expr, Total / ucParamCount(Expr)

End Sub

 

' Notice the double colon "::" instead of ":" for this type of definition.

' Be sure that the proper argument and return types (Double in this case) are used.

' "..." represents a variable number of arguments

ucDefine "Func:: MyAverage(x As Double ...) As Double", AddressOf MyAverage

 

New or Enhanced

 

Issues for users migrating from version 2.0

 

ucDefineFunction "FunctionName(ParamCount)", CodeAddress

 

Functions defined this way were faster than regular callback definitions.  However, you were limited to two arguments; and they could only be numeric.  Now, for even better efficiency, use NativeCall (an advanced Language Builder feature).  This supports any kind of data type, and any number of arguments.  NativeCall allows you to define the fastest kind of callback uCalc knows how to handle, with low overhead.  For instance, arithmetic operators, trig functions, etc... are defined this way in the include file.