NFun
NFun copied to clipboard
Exception: (Expected: UInt16, but was: UInt16)
Under most cases when working with UInt16 and Int16 types seem to have a bug saying it didn't receive what it expected even though the exception actually says it did receive the correct type.
I thought the casting of the input value before going into the runtime would help, but it didn't. Maybe there is some way for me to cast in the script that makes this work, but I tried that and was unable to fix the issue.
If there are any workarounds I could use in the meantime, please let me know.
Results from the following scripts
DoubleToDouble(input): Output out@2:Real = 2
FloatToFloat(input): Output out@2:Real = 2
Int32ToInt32(input): Output out@2:Int32 = 2
UInt32ToUInt32(input): Output out@2:UInt32 = 2
Int16ToInt16(input): Output out@2:Int16 = 2
UInt16ToUInt16(input): Output out@2:UInt16 = 2
DoubleToDouble(input + input): Output out@2:Real = 4
FloatToFloat(input + input): Output out@2:Real = 4
Int32ToInt32(input + input): Output out@2:Int32 = 4
UInt32ToUInt32(input + input): Output out@2:UInt32 = 4
Int16ToInt16(input + input): Unhandled exception. [FU783] Invalid function call argument: Int16ToInt16(Int16)->Int16. Expected: Int16, but was: Int16
UInt16ToUInt16(input + input): Unhandled exception. [FU783] Invalid function call argument: UInt16ToUInt16(UInt16)->UInt16. Expected: UInt16, but was: UInt16
public static void Main()
{
string script = "UInt16ToUInt16(input + input)";
var runtime = Funny.Hardcore
.WithFunction(nameof(DoubleToDouble), (double number) => DoubleToDouble(number))
.WithFunction(nameof(FloatToFloat), (float number) => FloatToFloat(number))
.WithFunction(nameof(Int32ToInt32), (Int32 number) => Int32ToInt32(number))
.WithFunction(nameof(UInt32ToUInt32), (UInt32 number) => UInt32ToUInt32(number))
.WithFunction(nameof(Int16ToInt16), (Int16 number) => Int16ToInt16(number))
.WithFunction(nameof(UInt16ToUInt16), (UInt16 number) => UInt16ToUInt16(number))
.Build(script);
runtime["input"].Value = (UInt16)2;
runtime.Run();
Console.WriteLine(runtime["out"]);
}
private static double DoubleToDouble(double number) => number;
private static float FloatToFloat(float number) => number;
private static Int32 Int32ToInt32(Int32 number) => number;
private static UInt32 UInt32ToUInt32(UInt32 number) => number;
private static Int16 Int16ToInt16(Int16 number) => number;
private static UInt16 UInt16ToUInt16(UInt16 number) => number;
The workaround I have found so far is to just take a double for every argument and cast it straight away to whatever I actually wanted to accept. It's awful, but it works for now.
public static void Main()
{
string script = "UInt16ToUInt16(input + input)";
var runtime = Funny.Hardcore
.WithFunction(nameof(DoubleToDouble), (double number) => DoubleToDouble(number))
.WithFunction(nameof(FloatToFloat), (double number) => FloatToFloat(number))
.WithFunction(nameof(Int32ToInt32), (double number) => Int32ToInt32(number))
.WithFunction(nameof(UInt32ToUInt32), (double number) => UInt32ToUInt32(number))
.WithFunction(nameof(Int16ToInt16), (double number) => Int16ToInt16(number))
.WithFunction(nameof(UInt16ToUInt16), (double number) => UInt16ToUInt16(number))
.Build(script);
runtime["input"].Value = (UInt16)2;
runtime.Run();
Console.WriteLine(runtime["out"]);
}
private static double DoubleToDouble(double number) => number;
private static float FloatToFloat(double number) => (float)number;
private static Int32 Int32ToInt32(double number) => (Int32)number;
private static UInt32 UInt32ToUInt32(double number) => (UInt32)number;
private static Int16 Int16ToInt16(double number) => (Int16)number;
private static UInt16 UInt16ToUInt16(double number) => (UInt16)number;
Hi, thank for report. I discovered the issue and figure out that it is not a bug, but wrong error message text, and lack of diallect settings
Actual Nfun error explanation
According to borring specification operator +
cannot be used for Int16
types, as it is defined only for arithmetical types (int32
int64
uint32
uint64
real
). This is done to protect against an overflow error, just as it is done in C#
So original problem is that in script UInt16ToUInt16(input + input)
expression input + input
can have only int32
or uint32
type. But function UInt16ToUInt16
has argument of uint16
. uint32
cannot be converted into uint16
so you have error
The same story for C# itself. Try to execute following C# code:
// C# code
UInt16 a = 0;
UInt16 b = 1;
F(a+b);//Error: Argument type 'int' is not assignable to parameter type 'short'
static UInt16 F(UInt16 x) => x;
Workaround
Use Int32 or Uint32 for your function paramers instead of Int16 or Uint16
Call to action
- To fix error message for your case
- To add new Dialect settings that allows overflow arithmetical operations for uint16/int16 to allow this code:
a:uint16 = 1
b:uint16 = 1
x:uint16 = a+b
y:uint16 = a-b
z:uint16 = a*b
Thank you so much for an amazing explanation so quickly. I was unaware that c# automatically converts UInt16/Int16 types.
Due to working with Modbus devices, I will be dealing with Uint16 and Uint16[] data types a lot. These Uint16/Uint16[] types in Modbus represent the raw Modbus registers that in tern make up whatever data types the manufacturer has deemed them to be used for (they quite often enjoy making up their own new data types).
I think my solution as you said is to use a larger data type as the function parameters to allow for manipulation of these values. But in the end, they will need to be converted back to Uint16/Uint16[] after the fact to fit into Modbus registers.
Thank you again. Please consider adding a donation link to this project so those who use NFun can support you.