DefineFunction

Method

Registers a user-defined function for use in expressions, supporting inline definitions, external callbacks, and advanced features like overloading and recursion.

Product: 

Class: 

Warning

uCalc API Preview Release Notice:The uCalc engine has successfully transitioned to modern cross-platform environments.The next phase envolves some structural changes, performance optimizations, and API refinements.The API is subject to breaking changes prior to the stable release. Please evaluate the preview version thoroughly before production use.

Syntax

DefineFunction(string, OpCallback, DataType, bool, bool)

Parameters

definition
string
The function signature and body, e.g., "MyFunc(x, y) = x + y".
functionAddr
OpCallback
(Default = 0)
The address of a native callback function that implements the function's logic. If provided, the expression body in the definition string is ignored.
returnType
DataType
(Default = Empty)
The return [DataType] of the function. If omitted, the type is often inferred from the expression body.
bootstrap
bool
(Default = false)
If true, allows the new function definition to call a pre-existing function of the same name, preventing recursion. Useful for wrapping or extending existing functions.
overwrite
bool
(Default = false)
If true, this definition replaces any existing function with the same signature, and automatically updates all previously parsed expressions that use it. Essential for reactive, spreadsheet-like behavior.

Return

Item

An [Item] object representing the newly defined function, which can be used for later modification or release.

Remarks

The DefineFunction method is a cornerstone of uCalc, allowing you to create custom functions for use in expressions. You can define functions in two primary ways:

  1. Inline Definition: Provide the entire function signature and logic as a single string.
  2. Callback Binding: Provide a function signature and link it to a native C#, C++, or VB function in your host application.

This flexibility makes it ideal for everything from simple user-defined helpers to complex integrations with existing code.

📖 Function Syntax

A function definition string follows this pattern:

FunctionName(param1, param2, ...) As ReturnType = expression

  • Parameters: A comma-separated list of parameter names. You can optionally assign a data type to a parameter by following it with As [typename]. Parentheses () are required even for functions with no parameters.
  • Return Type: Optional. If omitted, uCalc attempts to infer it. If it can't, it uses the instance's DefaultDataType.
  • Expression: The logic to be executed when the function is called.

⚙️ Core Features

FeatureDescription
OverloadingDefine multiple functions with the same name but different parameter types or counts. uCalc selects the correct one at runtime based on the arguments provided.
Optional ParametersSpecify default values for parameters, e.g., MyFunc(x, y = 5).
Variadic FunctionsCreate functions that accept a variable number of arguments using the ... syntax, e.g., Average(x ...)
RecursionFunctions can call themselves, enabling classic recursive algorithms like factorial or Fibonacci.
Shadowing vs. OverwritingBy default, a new definition shadows an old one; existing expressions still use the old version. Setting overwrite: true replaces the old definition everywhere, enabling powerful spreadsheet-like reactive updates.
BootstrappingSetting bootstrap: true lets you redefine a function by calling the original version within its new definition, which is perfect for extending or wrapping built-in functions without causing a recursive loop.

🔗 Argument Passing Modifiers

uCalc extends standard argument passing with powerful custom modifiers that provide deep introspection and control.

ModifierDescription
ByVal(Default) Passes the evaluated result of the argument.
ByRefPasses a reference to a variable, allowing the function to modify its value.
ByHandlePasses the argument's underlying Item object. This allows the callback to inspect metadata like the argument's name, data type, or original expression text.
ByExprPasses the argument as an unevaluated Expression object. This enables powerful lazy-evaluation and short-circuiting logic, as seen in the built-in IIf function.

💡 Comparative Analysis

  • vs. Compiled Languages (C#/C++): The primary advantage is dynamism. Functions can be defined at runtime from user input, configuration files, or database entries without requiring recompilation. This is fundamental for applications like report generators, scripting environments, and scientific modelers.

  • vs. Other Scripting Engines (Lua, Python): While full scripting engines are more powerful, they are also much heavier. uCalc is a lightweight, specialized component. Its key differentiators are:

    • ByExpr and ByHandle: These provide metaprogramming capabilities that are often complex or impossible to achieve in other embedded script engines.
    • Overwrite Flag: This built-in feature for creating reactive dependencies is a unique and powerful concept that simplifies building spreadsheet-like applications, a task that would require significant manual dependency tracking in other systems.

📋 Retrieving Defined Functions

You can get a list of all currently defined functions using uc.ListOfItems(ItemIs.Function).

Examples

A minimal example defining a function inline to calculate the area of a rectangle.

ID: 296

				
					using uCalcSoftware;

var uc = new uCalc();
uc.DefineVariable("x = 5");
uc.DefineFunction("Area(length, width) = length * width");
Console.WriteLine(uc.Eval("Area(4, x) + 7"));
				
			
27
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uc.DefineVariable("x = 5");
   uc.DefineFunction("Area(length, width) = length * width");
   cout << uc.Eval("Area(4, x) + 7") << endl;
}
				
			
27
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineVariable("x = 5")
      uc.DefineFunction("Area(length, width) = length * width")
      Console.WriteLine(uc.Eval("Area(4, x) + 7"))
   End Sub
End Module
				
			
27
Demonstrates defining a function that is implemented by a native callback in the host application.

ID: 297

				
					using uCalcSoftware;

var uc = new uCalc();

static void MyAreaCallback(uCalc.Callback cb) {
   var length = cb.Arg(1);
   var width = cb.Arg(2);
   cb.Return(length * width);
}


// The signature is defined, but the logic is provided by 'MyAreaCallback'.
uc.DefineFunction("Area(x, y)", MyAreaCallback);
Console.WriteLine(uc.Eval("Area(3, 4)"));
				
			
12
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call MyAreaCallback(uCalcBase::Callback cb) {
   auto length = cb.Arg(1);
   auto width = cb.Arg(2);
   cb.Return(length * width);
}

int main() {
   uCalc uc;
   // The signature is defined, but the logic is provided by 'MyAreaCallback'.
   uc.DefineFunction("Area(x, y)", MyAreaCallback);
   cout << uc.Eval("Area(3, 4)") << endl;
}
				
			
12
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub MyAreaCallback(ByVal cb As uCalc.Callback)
      Dim length = cb.Arg(1)
      Dim width = cb.Arg(2)
      cb.Return(length * width)
   End Sub
   
   Public Sub Main()
      Dim uc As New uCalc()
      '// The signature is defined, but the logic is provided by 'MyAreaCallback'.
      uc.DefineFunction("Area(x, y)", AddressOf MyAreaCallback)
      Console.WriteLine(uc.Eval("Area(3, 4)"))
   End Sub
End Module
				
			
12
Shows how to create overloaded functions that uCalc distinguishes based on parameter count and type.

ID: 298

				
					using uCalcSoftware;

var uc = new uCalc();
// Overload for two numbers
uc.DefineFunction("Combine(x, y) = x + y");

// Overload for two strings
uc.DefineFunction("Combine(x As String, y As String) As String = x + y");

// Overload for three numbers
uc.DefineFunction("Combine(x, y, z) = x + y + z");

Console.WriteLine($"Two numbers: {uc.EvalStr("Combine(5, 10)")}");
Console.WriteLine($"Two strings: {uc.EvalStr("Combine('Hello, ', 'World!')")}");
Console.WriteLine($"Three numbers: {uc.EvalStr("Combine(5, 10, 20)")}");
				
			
Two numbers: 15
Two strings: Hello, World!
Three numbers: 35
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   // Overload for two numbers
   uc.DefineFunction("Combine(x, y) = x + y");

   // Overload for two strings
   uc.DefineFunction("Combine(x As String, y As String) As String = x + y");

   // Overload for three numbers
   uc.DefineFunction("Combine(x, y, z) = x + y + z");

   cout << "Two numbers: " << uc.EvalStr("Combine(5, 10)") << endl;
   cout << "Two strings: " << uc.EvalStr("Combine('Hello, ', 'World!')") << endl;
   cout << "Three numbers: " << uc.EvalStr("Combine(5, 10, 20)") << endl;
}
				
			
Two numbers: 15
Two strings: Hello, World!
Three numbers: 35
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// Overload for two numbers
      uc.DefineFunction("Combine(x, y) = x + y")
      
      '// Overload for two strings
      uc.DefineFunction("Combine(x As String, y As String) As String = x + y")
      
      '// Overload for three numbers
      uc.DefineFunction("Combine(x, y, z) = x + y + z")
      
      Console.WriteLine($"Two numbers: {uc.EvalStr("Combine(5, 10)")}")
      Console.WriteLine($"Two strings: {uc.EvalStr("Combine('Hello, ', 'World!')")}")
      Console.WriteLine($"Three numbers: {uc.EvalStr("Combine(5, 10, 20)")}")
   End Sub
End Module
				
			
Two numbers: 15
Two strings: Hello, World!
Three numbers: 35
Defines a recursive Factorial function using the IIf function for conditional logic.

ID: 299

				
					using uCalcSoftware;

var uc = new uCalc();
uc.DefineFunction("Factorial(n) = IIf(n > 1, n * Factorial(n - 1), 1)");
Console.WriteLine(uc.Eval("Factorial(5)"));
				
			
120
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uc.DefineFunction("Factorial(n) = IIf(n > 1, n * Factorial(n - 1), 1)");
   cout << uc.Eval("Factorial(5)") << endl;
}
				
			
120
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineFunction("Factorial(n) = IIf(n > 1, n * Factorial(n - 1), 1)")
      Console.WriteLine(uc.Eval("Factorial(5)"))
   End Sub
End Module
				
			
120
Miscellaneous end-user functions defined with DefineFunction()

ID: 10

				
					using uCalcSoftware;

var uc = new uCalc();
Console.WriteLine("---- Simple function def ----");
uc.DefineFunction("f(x) = x ^ 2 + 5");
Console.WriteLine(uc.Eval("f(10)"));

Console.WriteLine("---- Function overloading ----");
// Overloading based on parameter type or number of parameters
uc.DefineFunction("MyOverload(x As Double) = x + x");
uc.DefineFunction("MyOverload(x As String) As String = x + x");
uc.DefineFunction("MyOverload(x As String, y As String) As String = x + y");
uc.DefineFunction("MyOverload(x, y) = x + y");
Console.WriteLine(uc.EvalStr("MyOverload(5)"));
Console.WriteLine(uc.EvalStr("MyOverload('Ha')"));
Console.WriteLine(uc.EvalStr("MyOverload('Hello ', 'world!')"));
Console.WriteLine(uc.EvalStr("MyOverload(5, 10)"));

Console.WriteLine("---- Definition hiding/un-hiding ----");
// Shadowing (hiding) definitions
uc.DefineFunction("h(x) = x * 10");
Console.WriteLine(uc.Eval("h(3)"));
var hFunc = uc.DefineFunction("h(x) = x * 100"); // hides previous def
Console.WriteLine(uc.Eval("h(3)"));
hFunc.Release(); // Releasing this restores previous def
Console.WriteLine(uc.Eval("h(3)"));

Console.WriteLine("---- Optional parameters ----");
uc.DefineFunction("Opt(x, y = 5, z As String = 'Hello') = x + y + Length(z)");
Console.WriteLine(uc.Eval("Opt(10)"));
Console.WriteLine(uc.Eval("Opt(10, 20)"));
Console.WriteLine(uc.Eval("Opt(10, 20, 'Just a test 123')"));

Console.WriteLine("---- Recursion ----");
uc.DefineFunction("Factorial(x) = iif(x > 1, x * Factorial(x - 1), 1)");
uc.DefineFunction("Fib(n) = IIf(n < 2, n, Fib(n - 1) + Fib(n - 2))");
Console.WriteLine(uc.Eval("Factorial(5)"));
Console.WriteLine(uc.Eval("Fib(10)"));

// Bootstrap - builds new def on top of existing one
Console.WriteLine("------ Bootstrapping -------");
Console.WriteLine(uc.EvalStr("Hex(123)")); // uses "built-in" version of Hex()

var MyHex = uc.DefineFunction("Hex(number As Int) As String = '0x' + UCase(Hex(number))", bootstrap: true);

Console.WriteLine(uc.EvalStr("Hex(123)"));
MyHex.Release();
Console.WriteLine(uc.EvalStr("Hex(123)"));

// Overwrite - useful for spreadsheet-like functionality
Console.WriteLine("------ Overwrite -------");

uc.DefineFunction("SpreadsheetCell_A1() = 5", overwrite: true);
uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 10", overwrite: true);
uc.DefineFunction("SpreadsheetCell_C3() = SpreadsheetCell_A1() + SpreadsheetCell_B2()", overwrite: true);

Console.WriteLine(uc.Eval("SpreadsheetCell_A1()"));
Console.WriteLine(uc.Eval("SpreadsheetCell_B2()"));
Console.WriteLine(uc.Eval("SpreadsheetCell_C3()"));
// SpreadsheetCell_C3() will be affected by the definition changes of SpreadsheetCell_A1() and  SpreadsheetCell_B3()

uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 100", overwrite: true);
uc.DefineFunction("SpreadsheetCell_A1() = 25", overwrite: true);

Console.WriteLine("-------");
// Note: Empty parenthesis are optional for functions with no parameters
Console.WriteLine(uc.Eval("SpreadsheetCell_A1"));
Console.WriteLine(uc.Eval("SpreadsheetCell_B2"));
Console.WriteLine(uc.Eval("SpreadsheetCell_C3"));

// See Define() topic for more





				
			
---- Simple function def ----
105
---- Function overloading ----
10
HaHa
Hello world!
15
---- Definition hiding/un-hiding ----
30
300
30
---- Optional parameters ----
20
35
45
---- Recursion ----
120
55
------ Bootstrapping -------
7b
0x7B
7b
------ Overwrite -------
5
50
55
-------
25
2500
2525
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   cout << "---- Simple function def ----" << endl;
   uc.DefineFunction("f(x) = x ^ 2 + 5");
   cout << uc.Eval("f(10)") << endl;

   cout << "---- Function overloading ----" << endl;
   // Overloading based on parameter type or number of parameters
   uc.DefineFunction("MyOverload(x As Double) = x + x");
   uc.DefineFunction("MyOverload(x As String) As String = x + x");
   uc.DefineFunction("MyOverload(x As String, y As String) As String = x + y");
   uc.DefineFunction("MyOverload(x, y) = x + y");
   cout << uc.EvalStr("MyOverload(5)") << endl;
   cout << uc.EvalStr("MyOverload('Ha')") << endl;
   cout << uc.EvalStr("MyOverload('Hello ', 'world!')") << endl;
   cout << uc.EvalStr("MyOverload(5, 10)") << endl;

   cout << "---- Definition hiding/un-hiding ----" << endl;
   // Shadowing (hiding) definitions
   uc.DefineFunction("h(x) = x * 10");
   cout << uc.Eval("h(3)") << endl;
   auto hFunc = uc.DefineFunction("h(x) = x * 100"); // hides previous def
   cout << uc.Eval("h(3)") << endl;
   hFunc.Release(); // Releasing this restores previous def
   cout << uc.Eval("h(3)") << endl;

   cout << "---- Optional parameters ----" << endl;
   uc.DefineFunction("Opt(x, y = 5, z As String = 'Hello') = x + y + Length(z)");
   cout << uc.Eval("Opt(10)") << endl;
   cout << uc.Eval("Opt(10, 20)") << endl;
   cout << uc.Eval("Opt(10, 20, 'Just a test 123')") << endl;

   cout << "---- Recursion ----" << endl;
   uc.DefineFunction("Factorial(x) = iif(x > 1, x * Factorial(x - 1), 1)");
   uc.DefineFunction("Fib(n) = IIf(n < 2, n, Fib(n - 1) + Fib(n - 2))");
   cout << uc.Eval("Factorial(5)") << endl;
   cout << uc.Eval("Fib(10)") << endl;

   // Bootstrap - builds new def on top of existing one
   cout << "------ Bootstrapping -------" << endl;
   cout << uc.EvalStr("Hex(123)") << endl; // uses "built-in" version of Hex()
   auto MyHex = uc.DefineFunction("Hex(number As Int) As String = '0x' + UCase(Hex(number))", 0, uCalc::DataType::Empty, true);


   cout << uc.EvalStr("Hex(123)") << endl;
   MyHex.Release();
   cout << uc.EvalStr("Hex(123)") << endl;

   // Overwrite - useful for spreadsheet-like functionality
   cout << "------ Overwrite -------" << endl;
   uc.DefineFunction("SpreadsheetCell_A1() = 5", 0, uCalc::DataType::Empty, false, true);
   uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 10", 0, uCalc::DataType::Empty, false, true);
   uc.DefineFunction("SpreadsheetCell_C3() = SpreadsheetCell_A1() + SpreadsheetCell_B2()", 0, uCalc::DataType::Empty, false, true);


   cout << uc.Eval("SpreadsheetCell_A1()") << endl;
   cout << uc.Eval("SpreadsheetCell_B2()") << endl;
   cout << uc.Eval("SpreadsheetCell_C3()") << endl;
   // SpreadsheetCell_C3() will be affected by the definition changes of SpreadsheetCell_A1() and  SpreadsheetCell_B3()
   uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 100", 0, uCalc::DataType::Empty, false, true);
   uc.DefineFunction("SpreadsheetCell_A1() = 25", 0, uCalc::DataType::Empty, false, true);


   cout << "-------" << endl;
   // Note: Empty parenthesis are optional for functions with no parameters
   cout << uc.Eval("SpreadsheetCell_A1") << endl;
   cout << uc.Eval("SpreadsheetCell_B2") << endl;
   cout << uc.Eval("SpreadsheetCell_C3") << endl;

   // See Define() topic for more





}
				
			
---- Simple function def ----
105
---- Function overloading ----
10
HaHa
Hello world!
15
---- Definition hiding/un-hiding ----
30
300
30
---- Optional parameters ----
20
35
45
---- Recursion ----
120
55
------ Bootstrapping -------
7b
0x7B
7b
------ Overwrite -------
5
50
55
-------
25
2500
2525
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Console.WriteLine("---- Simple function def ----")
      uc.DefineFunction("f(x) = x ^ 2 + 5")
      Console.WriteLine(uc.Eval("f(10)"))
      
      Console.WriteLine("---- Function overloading ----")
      '// Overloading based on parameter type or number of parameters
      uc.DefineFunction("MyOverload(x As Double) = x + x")
      uc.DefineFunction("MyOverload(x As String) As String = x + x")
      uc.DefineFunction("MyOverload(x As String, y As String) As String = x + y")
      uc.DefineFunction("MyOverload(x, y) = x + y")
      Console.WriteLine(uc.EvalStr("MyOverload(5)"))
      Console.WriteLine(uc.EvalStr("MyOverload('Ha')"))
      Console.WriteLine(uc.EvalStr("MyOverload('Hello ', 'world!')"))
      Console.WriteLine(uc.EvalStr("MyOverload(5, 10)"))
      
      Console.WriteLine("---- Definition hiding/un-hiding ----")
      '// Shadowing (hiding) definitions
      uc.DefineFunction("h(x) = x * 10")
      Console.WriteLine(uc.Eval("h(3)"))
      Dim hFunc = uc.DefineFunction("h(x) = x * 100") '// hides previous def
      Console.WriteLine(uc.Eval("h(3)"))
      hFunc.Release() '// Releasing this restores previous def
      Console.WriteLine(uc.Eval("h(3)"))
      
      Console.WriteLine("---- Optional parameters ----")
      uc.DefineFunction("Opt(x, y = 5, z As String = 'Hello') = x + y + Length(z)")
      Console.WriteLine(uc.Eval("Opt(10)"))
      Console.WriteLine(uc.Eval("Opt(10, 20)"))
      Console.WriteLine(uc.Eval("Opt(10, 20, 'Just a test 123')"))
      
      Console.WriteLine("---- Recursion ----")
      uc.DefineFunction("Factorial(x) = iif(x > 1, x * Factorial(x - 1), 1)")
      uc.DefineFunction("Fib(n) = IIf(n < 2, n, Fib(n - 1) + Fib(n - 2))")
      Console.WriteLine(uc.Eval("Factorial(5)"))
      Console.WriteLine(uc.Eval("Fib(10)"))
      
      '// Bootstrap - builds new def on top of existing one
      Console.WriteLine("------ Bootstrapping -------")
      Console.WriteLine(uc.EvalStr("Hex(123)")) '// uses "built-in" version of Hex()
      
      
      Dim MyHex = uc.DefineFunction("Hex(number As Int) As String = '0x' + UCase(Hex(number))", bootstrap:=True)
      Console.WriteLine(uc.EvalStr("Hex(123)"))
      MyHex.Release()
      Console.WriteLine(uc.EvalStr("Hex(123)"))
      
      '// Overwrite - useful for spreadsheet-like functionality
      Console.WriteLine("------ Overwrite -------")
      
      
      uc.DefineFunction("SpreadsheetCell_A1() = 5", overwrite:=true)
      uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 10", Overwrite:=true)
      uc.DefineFunction("SpreadsheetCell_C3() = SpreadsheetCell_A1() + SpreadsheetCell_B2()", overwrite:=true)
      Console.WriteLine(uc.Eval("SpreadsheetCell_A1()"))
      Console.WriteLine(uc.Eval("SpreadsheetCell_B2()"))
      Console.WriteLine(uc.Eval("SpreadsheetCell_C3()"))
      '// SpreadsheetCell_C3() will be affected by the definition changes of SpreadsheetCell_A1() and  SpreadsheetCell_B3()
      
      
      uc.DefineFunction("SpreadsheetCell_B2() = SpreadsheetCell_A1() * 100", overwrite:=true)
      uc.DefineFunction("SpreadsheetCell_A1() = 25", overwrite:=true)
      Console.WriteLine("-------")
      '// Note: Empty parenthesis are optional for functions with no parameters
      Console.WriteLine(uc.Eval("SpreadsheetCell_A1"))
      Console.WriteLine(uc.Eval("SpreadsheetCell_B2"))
      Console.WriteLine(uc.Eval("SpreadsheetCell_C3"))
      
      '// See Define() topic for more
      
      
      
      
      
   End Sub
End Module
				
			
---- Simple function def ----
105
---- Function overloading ----
10
HaHa
Hello world!
15
---- Definition hiding/un-hiding ----
30
300
30
---- Optional parameters ----
20
35
45
---- Recursion ----
120
55
------ Bootstrapping -------
7b
0x7B
7b
------ Overwrite -------
5
50
55
-------
25
2500
2525
Defining a callback function with a variable number of arguments

ID: 12

				
					using uCalcSoftware;

var uc = new uCalc();

static void MyAverage(uCalc.Callback cb) {
   double Total = 0;
   for (int x = 1; x <= cb.ArgCount(); x++) {
      Total = Total + cb.Arg(x);
   }
   cb.Return(Total / cb.ArgCount());
}

uc.DefineFunction("Average(x ...)", MyAverage);
Console.WriteLine(uc.Eval("Average(10, 3, 7, 4)"));
				
			
6
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call MyAverage(uCalcBase::Callback cb) {
   double Total = 0;
   for (int x = 1; x <= cb.ArgCount(); x++) {
      Total = Total + cb.Arg(x);
   }
   cb.Return(Total / cb.ArgCount());
}
int main() {
   uCalc uc;
   uc.DefineFunction("Average(x ...)", MyAverage);
   cout << uc.Eval("Average(10, 3, 7, 4)") << endl;
}
				
			
6
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub MyAverage(ByVal cb As uCalc.Callback)
      Dim Total As Double = 0
      For x  As Integer = 1 To cb.ArgCount()
         Total = Total + cb.Arg(x)
      Next
      cb.Return(Total / cb.ArgCount())
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineFunction("Average(x ...)", AddressOf MyAverage)
      Console.WriteLine(uc.Eval("Average(10, 3, 7, 4)"))
   End Sub
End Module
				
			
6
Passing arg ByHandle to retrieve meta data such as arg data type; and AnyType

ID: 13

				
					using uCalcSoftware;

var uc = new uCalc();

static void DisplayArgs(uCalc.Callback cb) {
   for (int x = 1; x <= cb.ArgCount(); x++) {
      Console.WriteLine(cb.ArgItem(x).ValueStr() + "  Type: " + cb.ArgItem(x).DataType.Name);
   }
}

uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs);
uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))");
				
			
5  Type: double
3+2i  Type: complex
Hello  Type: string
true  Type: bool
false  Type: bool
9  Type: int16
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call DisplayArgs(uCalcBase::Callback cb) {
   for (int x = 1; x <= cb.ArgCount(); x++) {
      cout << cb.ArgItem(x).ValueStr() + "  Type: " + cb.ArgItem(x).DataType().Name() << endl;
   }
}
int main() {
   uCalc uc;
   uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs);
   uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))");
}
				
			
5  Type: double
3+2i  Type: complex
Hello  Type: string
true  Type: bool
false  Type: bool
9  Type: int16
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub DisplayArgs(ByVal cb As uCalc.Callback)
      For x  As Integer = 1 To cb.ArgCount()
         Console.WriteLine(cb.ArgItem(x).ValueStr() + "  Type: " + cb.ArgItem(x).DataType.Name)
      Next
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", AddressOf DisplayArgs)
      uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))")
   End Sub
End Module
				
			
5  Type: double
3+2i  Type: complex
Hello  Type: string
true  Type: bool
false  Type: bool
9  Type: int16
Passing arg ByExpr (delayed lazy eval) and ByHandle

ID: 14

				
					using uCalcSoftware;

var uc = new uCalc();

static void MySum(uCalc.Callback cb) {
   var Total = 0.0;
   var Expr = cb.ArgExpr(1);
   var Start = cb.Arg(2);
   var Finish = cb.Arg(3);
   var Variable = cb.ArgItem(4);

   for (double x = Start; x <= Finish; x++) {
      Variable.Value(x);
      Total += Expr.Evaluate();
   }
   cb.Return(Total);
}

uc.DefineVariable("x");
uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum);
Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)"));

				
			
385
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call MySum(uCalcBase::Callback cb) {
   auto Total = 0.0;
   auto Expr = cb.ArgExpr(1);
   auto Start = cb.Arg(2);
   auto Finish = cb.Arg(3);
   auto Variable = cb.ArgItem(4);

   for (double x = Start; x <= Finish; x++) {
      Variable.Value(x);
      Total += Expr.Evaluate();
   }
   cb.Return(Total);
}
int main() {
   uCalc uc;
   uc.DefineVariable("x");
   uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum);
   cout << uc.Eval("Sum(x ^ 2, 1, 10, x)") << endl;

}
				
			
385
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub MySum(ByVal cb As uCalc.Callback)
      Dim Total = 0.0
      Dim Expr = cb.ArgExpr(1)
      Dim Start = cb.Arg(2)
      Dim Finish = cb.Arg(3)
      Dim Variable = cb.ArgItem(4)
      
      For x  As Double = Start To Finish
         Variable.Value(x)
         Total += Expr.Evaluate()
      Next
      cb.Return(Total)
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineVariable("x")
      uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", AddressOf MySum)
      Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)"))
      
   End Sub
End Module
				
			
385
Returning a string (from a callback)

ID: 15

				
					using uCalcSoftware;

var uc = new uCalc();

static void TwiceStr(uCalc.Callback cb) {
   cb.ReturnStr(cb.ArgStr(1) + cb.ArgStr(1));
}

uc.DefineFunction("Twice(Txt As String) As String", TwiceStr);
Console.WriteLine(uc.EvalStr("Twice('Bye')"));
				
			
ByeBye
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call TwiceStr(uCalcBase::Callback cb) {
   cb.ReturnStr(cb.ArgStr(1) + cb.ArgStr(1));
}
int main() {
   uCalc uc;
   uc.DefineFunction("Twice(Txt As String) As String", TwiceStr);
   cout << uc.EvalStr("Twice('Bye')") << endl;
}
				
			
ByeBye
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub TwiceStr(ByVal cb As uCalc.Callback)
      cb.ReturnStr(cb.ArgStr(1) + cb.ArgStr(1))
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineFunction("Twice(Txt As String) As String", AddressOf TwiceStr)
      Console.WriteLine(uc.EvalStr("Twice('Bye')"))
   End Sub
End Module
				
			
ByeBye
How to handle and retrieve various data types (including pointers) within a callback.

ID: 16

				
					using uCalcSoftware;

var uc = new uCalc();

static void MyFunction(uCalc.Callback cb) {
   var uc = cb.uCalc;
   Console.WriteLine("------ MyFunc ------");

   // Retrieve standard 32-bit and 64-bit integer arguments directly
   Console.WriteLine(cb.ArgInt32(1));
   Console.WriteLine(cb.ArgInt64(2));

   // Retrieve the value of a pointer argument by referencing its exact data type.
   Console.WriteLine(uc.ItemOf("Int8").DataType.ToString(cb.ArgAddr(3)));

   // The Item object correctly identifies the type before conversion
   Console.WriteLine(uc.ItemOf("Int").DataType.ToString(cb.ArgPtr(4)));
}

static void MyFunction2(uCalc.Callback cb) {
   var uc = cb.uCalc;
   Console.WriteLine("------ MyFunc2 ------");
   Console.WriteLine(uc.DataTypeOf(BuiltInType.Integer_8).ToString(cb.ArgPtr(1)));
}

static void MyFunction3(uCalc.Callback cb) {
   var uc = cb.uCalc;
   Console.WriteLine("------ MyFunc3 ------");
   Console.WriteLine(uc.DataTypeOf(BuiltInType.Integer_16).ToString(cb.ArgPtr(1)));
}

uc.DefineVariable("x As Int = 123"); // Int32
uc.DefineVariable("xPtr As Int Ptr = AddressOf(x)");
uc.DefineFunction("MyFunc(a As Int32, b As Int64, c As Byte, d As Int Ptr)", MyFunction);
uc.Eval("MyFunc(x*10, 1+1, 255, xPtr)");

uc.DefineVariable("x2 As Int8 = -123");
uc.DefineVariable("xPtr2 As Int8 Ptr = AddressOf(x2)");
uc.DefineFunction("MyFunc2(d As Int8 Ptr)", MyFunction2);
uc.Eval("MyFunc2(xPtr2)");

uc.DefineVariable("x3 As Int16 = 1234");
uc.DefineVariable("xPtr3 As Int16 Ptr = AddressOf(x3)");
uc.DefineFunction("MyFunc3(d As Int16 Ptr)", MyFunction3);
uc.Eval("MyFunc3(xPtr3)");
				
			
------ MyFunc ------
1230
2
-1
123
------ MyFunc2 ------
-123
------ MyFunc3 ------
1234
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call MyFunction(uCalcBase::Callback cb) {
   auto uc = cb.uCalc();
   cout << "------ MyFunc ------" << endl;

   // Retrieve standard 32-bit and 64-bit integer arguments directly
   cout << cb.ArgInt32(1) << endl;
   cout << cb.ArgInt64(2) << endl;

   // Retrieve the value of a pointer argument by referencing its exact data type.
   cout << uc.ItemOf("Int8").DataType().ToString(cb.ArgAddr(3)) << endl;

   // The Item object correctly identifies the type before conversion
   cout << uc.ItemOf("Int").DataType().ToString(cb.ArgPtr(4)) << endl;
}

void ucalc_call MyFunction2(uCalcBase::Callback cb) {
   auto uc = cb.uCalc();
   cout << "------ MyFunc2 ------" << endl;
   cout << uc.DataTypeOf(BuiltInType::Integer_8).ToString(cb.ArgPtr(1)) << endl;
}

void ucalc_call MyFunction3(uCalcBase::Callback cb) {
   auto uc = cb.uCalc();
   cout << "------ MyFunc3 ------" << endl;
   cout << uc.DataTypeOf(BuiltInType::Integer_16).ToString(cb.ArgPtr(1)) << endl;
}
int main() {
   uCalc uc;
   uc.DefineVariable("x As Int = 123"); // Int32
   uc.DefineVariable("xPtr As Int Ptr = AddressOf(x)");
   uc.DefineFunction("MyFunc(a As Int32, b As Int64, c As Byte, d As Int Ptr)", MyFunction);
   uc.Eval("MyFunc(x*10, 1+1, 255, xPtr)");

   uc.DefineVariable("x2 As Int8 = -123");
   uc.DefineVariable("xPtr2 As Int8 Ptr = AddressOf(x2)");
   uc.DefineFunction("MyFunc2(d As Int8 Ptr)", MyFunction2);
   uc.Eval("MyFunc2(xPtr2)");

   uc.DefineVariable("x3 As Int16 = 1234");
   uc.DefineVariable("xPtr3 As Int16 Ptr = AddressOf(x3)");
   uc.DefineFunction("MyFunc3(d As Int16 Ptr)", MyFunction3);
   uc.Eval("MyFunc3(xPtr3)");
}
				
			
------ MyFunc ------
1230
2
-1
123
------ MyFunc2 ------
-123
------ MyFunc3 ------
1234
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub MyFunction(ByVal cb As uCalc.Callback)
      Dim uc = cb.uCalc
      Console.WriteLine("------ MyFunc ------")
      
      '// Retrieve standard 32-bit and 64-bit integer arguments directly
      Console.WriteLine(cb.ArgInt32(1))
      Console.WriteLine(cb.ArgInt64(2))
      
      '// Retrieve the value of a pointer argument by referencing its exact data type.
      Console.WriteLine(uc.ItemOf("Int8").DataType.ToString(cb.ArgAddr(3)))
      
      '// The Item object correctly identifies the type before conversion
      Console.WriteLine(uc.ItemOf("Int").DataType.ToString(cb.ArgPtr(4)))
   End Sub
   
   Public Sub MyFunction2(ByVal cb As uCalc.Callback)
      Dim uc = cb.uCalc
      Console.WriteLine("------ MyFunc2 ------")
      Console.WriteLine(uc.DataTypeOf(BuiltInType.Integer_8).ToString(cb.ArgPtr(1)))
   End Sub
   
   Public Sub MyFunction3(ByVal cb As uCalc.Callback)
      Dim uc = cb.uCalc
      Console.WriteLine("------ MyFunc3 ------")
      Console.WriteLine(uc.DataTypeOf(BuiltInType.Integer_16).ToString(cb.ArgPtr(1)))
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineVariable("x As Int = 123") '// Int32
      uc.DefineVariable("xPtr As Int Ptr = AddressOf(x)")
      uc.DefineFunction("MyFunc(a As Int32, b As Int64, c As Byte, d As Int Ptr)", AddressOf MyFunction)
      uc.Eval("MyFunc(x*10, 1+1, 255, xPtr)")
      
      uc.DefineVariable("x2 As Int8 = -123")
      uc.DefineVariable("xPtr2 As Int8 Ptr = AddressOf(x2)")
      uc.DefineFunction("MyFunc2(d As Int8 Ptr)", AddressOf MyFunction2)
      uc.Eval("MyFunc2(xPtr2)")
      
      uc.DefineVariable("x3 As Int16 = 1234")
      uc.DefineVariable("xPtr3 As Int16 Ptr = AddressOf(x3)")
      uc.DefineFunction("MyFunc3(d As Int16 Ptr)", AddressOf MyFunction3)
      uc.Eval("MyFunc3(xPtr3)")
   End Sub
End Module
				
			
------ MyFunc ------
1230
2
-1
123
------ MyFunc2 ------
-123
------ MyFunc3 ------
1234
Determining properties of an expression part

ID: 40

				
					using uCalcSoftware;

var uc = new uCalc();

static void ItemCallback(uCalc.Callback cb) {
   Console.WriteLine($"Name: {cb.Item.Name}");
   Console.WriteLine($"Data type: {cb.Item.DataType.Name}");
   Console.WriteLine($"Param count: {cb.Item.Count}");
   Console.Write("Procedure type: ");
   if (cb.Item.IsProperty(ItemIs.Operator)) {
      Console.WriteLine("Operator");
   } else if (cb.Item.IsProperty(ItemIs.Function)) {
      Console.WriteLine("Function");
   }
   Console.WriteLine(cb.Item.Text);
   Console.WriteLine(cb.Item.Description);
   Console.WriteLine("---");
}


uc.DefineFunction("AAA() As Double", ItemCallback).Description = "Does this and that";
uc.DefineFunction("BBB(x, y, z) As String", ItemCallback).Description = "Does something else";
uc.DefineOperator("{x} CCC {y} As Int32", 0, Associativity.LeftToRight, ItemCallback);

uc.EvalStr("AAA()");
uc.EvalStr("BBB(9, 8, 7)");
uc.EvalStr("5 CCC 4");

				
			
Name: aaa
Data type: double
Param count: 0
Procedure type: Function
Function: AAA() As Double
Does this and that
---
Name: bbb
Data type: string
Param count: 3
Procedure type: Function
Function: BBB(x, y, z) As String
Does something else
---
Name: ccc
Data type: int
Param count: 2
Procedure type: Operator
Operator: {x} CCC {y} As Int32

---
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call ItemCallback(uCalcBase::Callback cb) {
   cout << "Name: " << cb.Item().Name() << endl;
   cout << "Data type: " << cb.Item().DataType().Name() << endl;
   cout << "Param count: " << cb.Item().Count() << endl;
   cout << "Procedure type: ";
   if (cb.Item().IsProperty(ItemIs::Operator)) {
      cout << "Operator" << endl;
   } else if (cb.Item().IsProperty(ItemIs::Function)) {
      cout << "Function" << endl;
   }
   cout << cb.Item().Text() << endl;
   cout << cb.Item().Description() << endl;
   cout << "---" << endl;
}
int main() {
   uCalc uc;

   uc.DefineFunction("AAA() As Double", ItemCallback).Description("Does this and that");
   uc.DefineFunction("BBB(x, y, z) As String", ItemCallback).Description("Does something else");
   uc.DefineOperator("{x} CCC {y} As Int32", 0, Associativity::LeftToRight, ItemCallback);

   uc.EvalStr("AAA()");
   uc.EvalStr("BBB(9, 8, 7)");
   uc.EvalStr("5 CCC 4");

}
				
			
Name: aaa
Data type: double
Param count: 0
Procedure type: Function
Function: AAA() As Double
Does this and that
---
Name: bbb
Data type: string
Param count: 3
Procedure type: Function
Function: BBB(x, y, z) As String
Does something else
---
Name: ccc
Data type: int
Param count: 2
Procedure type: Operator
Operator: {x} CCC {y} As Int32

---
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub ItemCallback(ByVal cb As uCalc.Callback)
      Console.WriteLine($"Name: {cb.Item.Name}")
      Console.WriteLine($"Data type: {cb.Item.DataType.Name}")
      Console.WriteLine($"Param count: {cb.Item.Count}")
      Console.Write("Procedure type: ")
      If cb.Item.IsProperty(ItemIs.Operator) Then
         Console.WriteLine("Operator")
         ElseIf cb.Item.IsProperty(ItemIs.Function ) Then
            Console.WriteLine("Function")
         End If
         Console.WriteLine(cb.Item.Text)
         Console.WriteLine(cb.Item.Description)
         Console.WriteLine("---")
      End Sub
      Public Sub Main()
         Dim uc As New uCalc()
         
         uc.DefineFunction("AAA() As Double", AddressOf ItemCallback).Description = "Does this and that"
         uc.DefineFunction("BBB(x, y, z) As String", AddressOf ItemCallback).Description = "Does something else"
         uc.DefineOperator("{x} CCC {y} As Int32", 0, Associativity.LeftToRight, AddressOf ItemCallback)
         
         uc.EvalStr("AAA()")
         uc.EvalStr("BBB(9, 8, 7)")
         uc.EvalStr("5 CCC 4")
         
      End Sub
   End Module
				
			
Name: aaa
Data type: double
Param count: 0
Procedure type: Function
Function: AAA() As Double
Does this and that
---
Name: bbb
Data type: string
Param count: 3
Procedure type: Function
Function: BBB(x, y, z) As String
Does something else
---
Name: ccc
Data type: int
Param count: 2
Procedure type: Operator
Operator: {x} CCC {y} As Int32

---
A quick start example showing defining a variable, a function, and evaluating an expression.

ID: 1296

				
					using uCalcSoftware;

var uc = new uCalc();
uc.DefineVariable("x = 10");
uc.DefineFunction("DoubleThis(n) = n * 2");

Console.WriteLine(uc.Eval("DoubleThis(x) + 5"));
				
			
25
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uc.DefineVariable("x = 10");
   uc.DefineFunction("DoubleThis(n) = n * 2");

   cout << uc.Eval("DoubleThis(x) + 5") << endl;
}
				
			
25
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      uc.DefineVariable("x = 10")
      uc.DefineFunction("DoubleThis(n) = n * 2")
      
      Console.WriteLine(uc.Eval("DoubleThis(x) + 5"))
   End Sub
End Module
				
			
25
Building an Equation Solver with the Parser and Transformer

ID: 1461

				
					using uCalcSoftware;

var uc = new uCalc();

static void EqSolveCb(uCalc.Callback cb) { // Callback based on the Bisection Method
   var expr = cb.ArgExpr(1);     // ByExpr: Unevaluated Expression object (lazy evaluation)
   var a = cb.Arg(2);            // Argument 2: Range Minimum
   var b = cb.Arg(3);            // Argument 3: Range Maximum
   var variable = cb.ArgItem(4); // ByHandle: The variable Item object

   // Helper to update the variable in the uCalc engine and evaluate the expression
   double EvaluateAt(double val) {
      variable.Value(val);   // Push the new test value to the variable
      return expr.Evaluate(); // Evaluate the pre-parsed expression
   }

   // Ensure f(a) < f(b) so we always know which direction to slide the bounds; swap a & b if necessary
   if (EvaluateAt(b) < EvaluateAt(a)) (a, b) = (b, a);

   var midpoint = 0.0;
   var fMidpoint = 0.0;

   // Bisection loop
   for (int i = 0; i <= 100; i++) {
      midpoint = (a + b) / 2;
      fMidpoint = EvaluateAt(midpoint);

      if (Math.Abs(fMidpoint) < 1e-7) break; // Stop if close enough to 0

      // Narrow the bounds (compact logic!)
      if (fMidpoint < 0) a = midpoint; else b = midpoint;
   }

   if (Math.Abs(fMidpoint) > 1e-5) cb.Error.Raise("No solution found in the given range.");
   cb.Return(Math.Round(midpoint, 7)); // Return the final solved value
}

// 1. Define variables that might be used by the end-user
uc.DefineVariable("x");
uc.DefineVariable("MyVar");

// 2. Transformer converts `EqSolve(L = R)` into `EqSolve(L - (R))` & sets defaults before it hits the parser
var t = uc.ExpressionTransformer;
t.FromTo("EqSolve({L} = {R} [[,]for {var}][, {min}, {max}])",
"EqSolve({L} - ({R}), {min}{!min:-10000}, {max}{!max: 10000}, {var}{!var: x})");

// 3. Define the custom function signature
uc.DefineFunction("EqSolve(ByExpr eq, min, max, ByHandle variable)", EqSolveCb);

// --- Demo Executions ---
System.Collections.Generic.List<string> eqList = new() {
   "EqSolve(x + 5 = 125)", // Using default range [-10000,10000]
   "EqSolve(x^2 + 5 = 105)", // Picks one result from the default range
   "EqSolve(x^2 + 5 = 105, 0, 100)", // Restricts to positive root
   "EqSolve(x^2 + 5 = 105, -100, 0)", // Restricts to negative root
   "EqSolve(x^2 + 1000 = 5)", // No existing solution
   "EqSolve(40 + MyVar * 6 = 88, for MyVar)" // Uses custom variable 'MyVar' instead of 'x'
};

foreach(var eq in eqList) {
   Console.WriteLine(uc.ExpressionTransformer.Transform(eq)); // Displays transformed expression
   Console.WriteLine($"Result: {uc.EvalStr(eq)}"); // Returns result
}
				
			
EqSolve(x + 5 - (125), -10000,  10000,  x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000,  10000,  x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100,  x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0,  x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000,  10000,  x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000,  10000, MyVar)
Result: 8
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call EqSolveCb(uCalcBase::Callback cb) { // Callback based on the Bisection Method
   auto expr = cb.ArgExpr(1);     // ByExpr: Unevaluated Expression object (lazy evaluation)
   auto a = cb.Arg(2);            // Argument 2: Range Minimum
   auto b = cb.Arg(3);            // Argument 3: Range Maximum
   auto variable = cb.ArgItem(4); // ByHandle: The variable Item object

   // Helper to update the variable in the uCalc engine and evaluate the expression
   auto EvaluateAt = [&](double val) -> double {
      variable.Value(val);
      return expr.Evaluate();
   };

   // Ensure f(a) < f(b) so we always know which direction to slide the bounds; swap a & b if necessary
   if (EvaluateAt(b) < EvaluateAt(a)) swap(a, b);

   auto midpoint = 0.0;
   auto fMidpoint = 0.0;

   // Bisection loop
   for (int i = 0; i <= 100; i++) {
      midpoint = (a + b) / 2;
      fMidpoint = EvaluateAt(midpoint);

      if (abs(fMidpoint) < 1e-7) break; // Stop if close enough to 0

      // Narrow the bounds (compact logic!)
      if (fMidpoint < 0) a = midpoint; else b = midpoint;
   }

   if (abs(fMidpoint) > 1e-5) cb.Error().Raise("No solution found in the given range.");
   cb.Return(round(midpoint * 10000000.0) / 10000000.0); // Return the final solved value
}
int main() {
   uCalc uc;
   // 1. Define variables that might be used by the end-user
   uc.DefineVariable("x");
   uc.DefineVariable("MyVar");

   // 2. Transformer converts `EqSolve(L = R)` into `EqSolve(L - (R))` & sets defaults before it hits the parser
   auto t = uc.ExpressionTransformer();
   t.FromTo("EqSolve({L} = {R} [[,]for {var}][, {min}, {max}])",
   "EqSolve({L} - ({R}), {min}{!min:-10000}, {max}{!max: 10000}, {var}{!var: x})");

   // 3. Define the custom function signature
   uc.DefineFunction("EqSolve(ByExpr eq, min, max, ByHandle variable)", EqSolveCb);

   // --- Demo Executions ---
   vector<string> eqList = {
      "EqSolve(x + 5 = 125)", // Using default range [-10000,10000]
      "EqSolve(x^2 + 5 = 105)", // Picks one result from the default range
      "EqSolve(x^2 + 5 = 105, 0, 100)", // Restricts to positive root
      "EqSolve(x^2 + 5 = 105, -100, 0)", // Restricts to negative root
      "EqSolve(x^2 + 1000 = 5)", // No existing solution
      "EqSolve(40 + MyVar * 6 = 88, for MyVar)" // Uses custom variable 'MyVar' instead of 'x'
   };

   for(auto eq : eqList) {
      cout << uc.ExpressionTransformer().Transform(eq) << endl; // Displays transformed expression
      cout << "Result: " << uc.EvalStr(eq) << endl; // Returns result
   }
}
				
			
EqSolve(x + 5 - (125), -10000,  10000,  x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000,  10000,  x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100,  x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0,  x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000,  10000,  x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000,  10000, MyVar)
Result: 8
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub EqSolveCb(ByVal cb As uCalc.Callback)REM // Callback based on the Bisection Method
      Dim expr = cb.ArgExpr(1)     '// ByExpr: Unevaluated Expression object (lazy evaluation)
      Dim a = cb.Arg(2)            '// Argument 2: Range Minimum
      Dim b = cb.Arg(3)            '// Argument 3: Range Maximum
      Dim variable = cb.ArgItem(4) '// ByHandle: The variable Item object
      
      '// Helper to update the variable in the uCalc engine and evaluate the expression
      Dim EvaluateAt = Function (val as Double) As Double
         variable.Value(val)   '// Push the new test value to the variable
         return expr.Evaluate() '// Evaluate the pre-parsed expression
      End Function
      
      '// Ensure f(a) < f(b) so we always know which direction to slide the bounds; swap a & b if necessary
      If EvaluateAt(b) < EvaluateAt(a) Then Dim temp = a : a = b : b = temp
         
         Dim midpoint = 0.0
         Dim fMidpoint = 0.0
         
         '// Bisection loop
         For i  As Integer = 0 To 100
            midpoint = (a + b) / 2
            fMidpoint = EvaluateAt(midpoint)
            
            If Math.Abs(fMidpoint) < 1e-7 Then Exit For REM // Stop if close enough to 0

      REM// Narrow the bounds (compact logic!)
               If fMidpoint < 0 Then a = midpoint Else b = midpoint
                  Next
                  
                  If Math.Abs(fMidpoint) > 1e-5 Then cb.Error.Raise("No solution found in the given range.")
                     cb.Return(Math.Round(midpoint, 7)) '// Return the final solved value 
                  End Sub
                  Public Sub Main()
                     Dim uc As New uCalc()
                     '// 1. Define variables that might be used by the end-user
                     uc.DefineVariable("x")
                     uc.DefineVariable("MyVar")
                     
                     '// 2. Transformer converts `EqSolve(L = R)` into `EqSolve(L - (R))` & sets defaults before it hits the parser
                     Dim t = uc.ExpressionTransformer
                     t.FromTo("EqSolve({L} = {R} [[,]for {var}][, {min}, {max}])",
                     "EqSolve({L} - ({R}), {min}{!min:-10000}, {max}{!max: 10000}, {var}{!var: x})")
                     
                     '// 3. Define the custom function signature
                     uc.DefineFunction("EqSolve(ByExpr eq, min, max, ByHandle variable)", AddressOf EqSolveCb)
                     
                     '// --- Demo Executions ---
                     Dim eqList As New List(Of String) From {
                     "EqSolve(x + 5 = 125)", '// Using default range [-10000,10000]
                     "EqSolve(x^2 + 5 = 105)", '// Picks one result from the default range
                     "EqSolve(x^2 + 5 = 105, 0, 100)", '// Restricts to positive root
                     "EqSolve(x^2 + 5 = 105, -100, 0)", '// Restricts to negative root
                     "EqSolve(x^2 + 1000 = 5)", '// No existing solution
                     "EqSolve(40 + MyVar * 6 = 88, for MyVar)" '// Uses custom variable 'MyVar' instead of 'x'
                     }
                     
                     For Each eq In eqList
                        Console.WriteLine(uc.ExpressionTransformer.Transform(eq)) '// Displays transformed expression
                        Console.WriteLine($"Result: {uc.EvalStr(eq)}") '// Returns result
                     Next
                  End Sub
               End Module
				
			
EqSolve(x + 5 - (125), -10000,  10000,  x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000,  10000,  x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100,  x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0,  x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000,  10000,  x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000,  10000, MyVar)
Result: 8

This page last modified on: 

8/19/2026