@Josep Roca, about Afx/CVar.inc

General FreeBASIC programming questions.
srvaldez
Posts: 2640
Joined: Sep 25, 2005 21:54

@Josep Roca, about Afx/CVar.inc

Postby srvaldez » Dec 10, 2020 11:08

hello Josep Roca
the following does not produce the result I would expect, any help is much appreciated
<edit> using the latest version from https://github.com/JoseRoca/WinFBX

Code: Select all

#include once "Afx/CVar.inc"

Dim As CVAR v1

v1 = 1
Print v1
v1 += 1
Print v1
v1 -= "1"
Print v1
v1 += 1.2345
Print v1
Sleep

ouput
1
2
2
51.2345
Last edited by srvaldez on Dec 10, 2020 12:07, edited 1 time in total.
jj2007
Posts: 1940
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: @Josep Roca, about Afx/CVar.inc

Postby jj2007 » Dec 10, 2020 11:52

I get different results with GAS, Gcc, FB64:

Code: Select all

1
2
2
3.2344999999999997
Strange. Btw compilation takes four times as long as for a 60 lines snippet that includes Windows.bi and crt.bi
srvaldez
Posts: 2640
Joined: Sep 25, 2005 21:54

Re: @Josep Roca, about Afx/CVar.inc

Postby srvaldez » Dec 10, 2020 12:09

Hi jj2007
are you using the latest Afx includes from https://github.com/JoseRoca/WinFBX ?
jj2007
Posts: 1940
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: @Josep Roca, about Afx/CVar.inc

Postby jj2007 » Dec 10, 2020 13:08

srvaldez wrote:Hi jj2007
are you using the latest Afx includes from https://github.com/JoseRoca/WinFBX ?
No, I used an older version. Now that I've downloaded the latest version, I get your results. The compile time issue persists - this snippet compiles ten times faster (and gives correct results):

Code: Select all

Dim As double v1
v1 = 1
Print v1
v1 += 1
Print v1
' v1 -= "1"  ' throws an error (and rightly so!)
Print v1
v1 += 1.2345
Print v1
Sleep
srvaldez
Posts: 2640
Joined: Sep 25, 2005 21:54

Re: @Josep Roca, about Afx/CVar.inc

Postby srvaldez » Dec 10, 2020 13:12

jj2007 wrote:

Code: Select all

' v1 -= "1"  ' throws an error (and rightly so!)

it throws no error here, here's a variation

Code: Select all

#include once "Afx/CVar.inc"

Dim As CVAR v1

v1 = 1
Print v1
v1 = v1 + 1
Print v1
v1 = v1 - "1"
Print v1
v1 = v1 + 1.2345
Print v1
Sleep

output
1
2
1
50.2345
jj2007
Posts: 1940
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: @Josep Roca, about Afx/CVar.inc

Postby jj2007 » Dec 10, 2020 13:48

Wow, not exactly the expected value...

As to throwing errors: I think it should. I have used the add somevar, "1" syntax often, but in Assembly. BASIC is another animal...

P.S., your variation:

Code: Select all

** SARG: compiling TmpFb.bas with -t 2000 -gen gas64 -g -Wc -O2 -s console **
reghandle reg=r11 not free vreg=11
reghandle reg=r11 not free vreg=16

*** compiling with Fb SARG took 1661 milliseconds ***
Josep Roca
Posts: 516
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: @Josep Roca, about Afx/CVar.inc

Postby Josep Roca » Dec 11, 2020 1:32

For some reason unknown to me, when passing a float value to a CVAR constructor, the compiler complains about an ambiguous call error, and when using v1 += 1.2345 it doesn't call the += operator, but does a cast to a WSTRING!

This works: v1 += CVAR(1.2345, "DOUBLE")
SARG
Posts: 1230
Joined: May 27, 2005 7:15
Location: FRANCE

Re: @Josep Roca, about Afx/CVar.inc

Postby SARG » Dec 12, 2020 1:19

Unless I don't understand but v1 -="1" also doesn't work as the value of v1 is still 2. Shouldn't it be 1 ?

@jj2007
Your report allowed me to fix a bug when converting a pointer to an integer. Thanks.
Josep Roca
Posts: 516
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: @Josep Roca, about Afx/CVar.inc

Postby Josep Roca » Dec 12, 2020 14:44

> Unless I don't understand but v1 -="1" also doesn't work as the value of v1 is still 2. Shouldn't it be 1 ?

It is ignored since "1" is not a number, but a string.
SARG
Posts: 1230
Joined: May 27, 2005 7:15
Location: FRANCE

Re: @Josep Roca, about Afx/CVar.inc

Postby SARG » Dec 12, 2020 18:17

Josep Roca wrote:It is ignored since "1" is not a number, but a string.
Ok but how to explain that in the variation by srvaldez : v1 = v1 - "1" gives the right value ?
jj2007
Posts: 1940
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: @Josep Roca, about Afx/CVar.inc

Postby jj2007 » Dec 12, 2020 20:07

Josep Roca wrote:It is ignored since "1" is not a number, but a string.
Shouldn't it throw an error instead of ignoring the "1"?
Josep Roca
Posts: 516
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: @Josep Roca, about Afx/CVar.inc

Postby Josep Roca » Dec 12, 2020 21:04

> Shouldn't it throw an error instead of ignoring the "1"?

How? It is an operator, not a function that can return a value.

Anyway, I have found the problem: the constructor CONSTRUCTOR CVar (BYVAL _value AS DOUBLE) conflicts with the constructor CONSTRUCTOR CVar (BYVAL _value AS DOUBLE, BYVAL _vType AS WORD = VT_R8) because the compiler can't ascertain which one must use since the second parameter of the second constructor is optional. Removing the constructor CONSTRUCTOR CVar (BYVAL _value AS DOUBLE) it works.
Josep Roca
Posts: 516
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: @Josep Roca, about Afx/CVar.inc

Postby Josep Roca » Dec 12, 2020 21:33

SARG wrote:
Josep Roca wrote:It is ignored since "1" is not a number, but a string.
Ok but how to explain that in the variation by srvaldez : v1 = v1 - "1" gives the right value ?


Because in the operator -, I call the API function VarSub without checking the type of the passed variants

Code: Select all

' ========================================================================================
PRIVATE OPERATOR - (BYREF cv1 AS CVAR, BYREF cv2 AS CVAR) AS CVAR
   ' // Subtract
   DIM cvRes AS CVAR
   VarSub(@cv1.vd, @cv2.vd, cvRes.vptr)
   OPERATOR = cvRes
END OPERATOR
' ========================================================================================


[VarSub tries to coerce the type of the variant passed if they are of different type]

whereas I do it in the operator -=

Code: Select all

' ========================================================================================
PRIVATE OPERATOR CVar.-= (BYREF cv AS CVAR)
   CVAR_DP("CVAR -=")
   IF vd.vt <> VT_BSTR AND cv.vd.vt <> VT_BSTR THEN
      DIM vRes AS VARIANT
      IF VarSub(@vd, @cv.vd, @vRes) = S_OK THEN VariantCopy(@vd, @vRes)
   END IF
END OPERATOR
' ========================================================================================


If I remove the check then it will work.

I never occurred to me to test the implemented operators substracting an string from a number.

Should I remove the checks?
Last edited by Josep Roca on Dec 13, 2020 2:58, edited 2 times in total.
Josep Roca
Posts: 516
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: @Josep Roca, about Afx/CVar.inc

Postby Josep Roca » Dec 12, 2020 21:49

These API functions that deal with variants do a lot of work.

For example, this is the C++ code for VarSub as implemented in ReactOS:

Code: Select all

HRESULT WINAPI VarSub   (   LPVARIANT    left,
LPVARIANT    right,
LPVARIANT    result
)      

 {
     HRESULT hres = S_OK;
     VARTYPE resvt = VT_EMPTY;
     VARTYPE leftvt,rightvt;
     VARTYPE rightExtraFlags,leftExtraFlags,ExtraFlags;
     VARIANT lv,rv;
     VARIANT tempLeft, tempRight;
 
     VariantInit(&lv);
     VariantInit(&rv);
     VariantInit(&tempLeft);
     VariantInit(&tempRight);
 
     TRACE("(%s,%s,%p)\n", debugstr_variant(left), debugstr_variant(right), result);
 
     if ((V_VT(left) & VT_TYPEMASK) == VT_DISPATCH &&
         (V_VT(left)&(~VT_TYPEMASK)) == 0 &&
         (V_VT(right) & VT_TYPEMASK) != VT_NULL)
     {
         if (NULL == V_DISPATCH(left)) {
             if ((V_VT(right) & VT_TYPEMASK) >= VT_INT_PTR)
                 hres = DISP_E_BADVARTYPE;
             else if ((V_VT(right) & VT_TYPEMASK) >= VT_UI8 &&
                 (V_VT(right) & VT_TYPEMASK) < VT_RECORD)
                 hres = DISP_E_BADVARTYPE;
             else switch (V_VT(right) & VT_TYPEMASK)
             {
             case VT_VARIANT:
             case VT_UNKNOWN:
             case 15:
             case VT_I1:
             case VT_UI2:
             case VT_UI4:
                 hres = DISP_E_BADVARTYPE;
             }
             if (FAILED(hres)) goto end;
         }
         hres = VARIANT_FetchDispatchValue(left, &tempLeft);
         if (FAILED(hres)) goto end;
         left = &tempLeft;
     }
     if ((V_VT(right) & VT_TYPEMASK) == VT_DISPATCH &&
         (V_VT(right)&(~VT_TYPEMASK)) == 0 &&
         (V_VT(left) & VT_TYPEMASK) != VT_NULL)
     {
         if (NULL == V_DISPATCH(right))
         {
             if ((V_VT(left) & VT_TYPEMASK) >= VT_INT_PTR)
                 hres = DISP_E_BADVARTYPE;
             else if ((V_VT(left) & VT_TYPEMASK) >= VT_UI8 &&
                 (V_VT(left) & VT_TYPEMASK) < VT_RECORD)
                 hres = DISP_E_BADVARTYPE;
             else switch (V_VT(left) & VT_TYPEMASK)
             {
             case VT_VARIANT:
             case VT_UNKNOWN:
             case 15:
             case VT_I1:
             case VT_UI2:
             case VT_UI4:
                 hres = DISP_E_BADVARTYPE;
             }
             if (FAILED(hres)) goto end;
         }
         hres = VARIANT_FetchDispatchValue(right, &tempRight);
         if (FAILED(hres)) goto end;
         right = &tempRight;
     }
 
     leftvt = V_VT(left)&VT_TYPEMASK;
     rightvt = V_VT(right)&VT_TYPEMASK;
     leftExtraFlags = V_VT(left)&(~VT_TYPEMASK);
     rightExtraFlags = V_VT(right)&(~VT_TYPEMASK);
 
     if (leftExtraFlags != rightExtraFlags)
     {
         hres = DISP_E_BADVARTYPE;
         goto end;
     }
     ExtraFlags = leftExtraFlags;
 
     /* determine return type and return code */
     /* All extra flags produce errors */
     if (ExtraFlags == (VT_VECTOR|VT_BYREF|VT_RESERVED) ||
         ExtraFlags == (VT_VECTOR|VT_RESERVED) ||
         ExtraFlags == (VT_VECTOR|VT_BYREF) ||
         ExtraFlags == (VT_BYREF|VT_RESERVED) ||
         ExtraFlags == VT_VECTOR ||
         ExtraFlags == VT_BYREF ||
         ExtraFlags == VT_RESERVED)
     {
         hres = DISP_E_BADVARTYPE;
         goto end;
     }
     else if (ExtraFlags >= VT_ARRAY)
     {
         hres = DISP_E_TYPEMISMATCH;
         goto end;
     }
     /* Native VarSub cannot handle: VT_I1, VT_UI2, VT_UI4,
        VT_INT, VT_UINT and VT_UI8. Tested with WinXP */
     else if (leftvt == VT_CLSID || rightvt == VT_CLSID ||
         leftvt == VT_VARIANT || rightvt == VT_VARIANT ||
         leftvt == VT_I1 || rightvt == VT_I1 ||
         leftvt == VT_UI2 || rightvt == VT_UI2 ||
         leftvt == VT_UI4 || rightvt == VT_UI4 ||
         leftvt == VT_UI8 || rightvt == VT_UI8 ||
         leftvt == VT_INT || rightvt == VT_INT ||
         leftvt == VT_UINT || rightvt == VT_UINT ||
         leftvt == VT_UNKNOWN || rightvt == VT_UNKNOWN ||
         leftvt == VT_RECORD || rightvt == VT_RECORD)
     {
         if (leftvt == VT_RECORD && rightvt == VT_I8)
             hres = DISP_E_TYPEMISMATCH;
         else if (leftvt < VT_UI1 && rightvt == VT_RECORD)
             hres = DISP_E_TYPEMISMATCH;
         else if (leftvt >= VT_UI1 && rightvt == VT_RECORD)
             hres = DISP_E_TYPEMISMATCH;
         else if (leftvt == VT_RECORD && rightvt <= VT_UI1)
             hres = DISP_E_TYPEMISMATCH;
         else if (leftvt == VT_RECORD && rightvt > VT_UI1)
             hres = DISP_E_BADVARTYPE;
         else
             hres = DISP_E_BADVARTYPE;
         goto end;
     }
     /*  The following flags/types are invalid for left variant */
     else if (!((leftvt <= VT_LPWSTR || leftvt == VT_RECORD ||
         leftvt == VT_CLSID) && leftvt != (VARTYPE)15 /* undefined vt */ &&
         (leftvt < VT_VOID || leftvt > VT_LPWSTR)))
     {
         hres = DISP_E_BADVARTYPE;
         goto end;
     }
     /*  The following flags/types are invalid for right variant */
     else if (!((rightvt <= VT_LPWSTR || rightvt == VT_RECORD ||
         rightvt == VT_CLSID) && rightvt != (VARTYPE)15 /* undefined vt */ &&
         (rightvt < VT_VOID || rightvt > VT_LPWSTR)))
     {
         hres = DISP_E_BADVARTYPE;
         goto end;
     }
     else if ((leftvt == VT_NULL && rightvt == VT_DISPATCH) ||
         (leftvt == VT_DISPATCH && rightvt == VT_NULL))
         resvt = VT_NULL;
     else if (leftvt == VT_DISPATCH || rightvt == VT_DISPATCH ||
         leftvt == VT_ERROR || rightvt == VT_ERROR)
     {
         hres = DISP_E_TYPEMISMATCH;
         goto end;
     }
     else if (leftvt == VT_NULL || rightvt == VT_NULL)
         resvt = VT_NULL;
     else if ((leftvt == VT_EMPTY && rightvt == VT_BSTR) ||
         (leftvt == VT_DATE && rightvt == VT_DATE) ||
         (leftvt == VT_BSTR && rightvt == VT_EMPTY) ||
         (leftvt == VT_BSTR && rightvt == VT_BSTR))
         resvt = VT_R8;
     else if (leftvt == VT_DECIMAL || rightvt == VT_DECIMAL)
         resvt = VT_DECIMAL;
     else if (leftvt == VT_DATE || rightvt == VT_DATE)
         resvt = VT_DATE;
     else if (leftvt == VT_CY || rightvt == VT_CY)
         resvt = VT_CY;
     else if (leftvt == VT_R8 || rightvt == VT_R8)
         resvt = VT_R8;
     else if (leftvt == VT_BSTR || rightvt == VT_BSTR)
         resvt = VT_R8;
     else if (leftvt == VT_R4 || rightvt == VT_R4)
     {
         if (leftvt == VT_I4 || rightvt == VT_I4 ||
             leftvt == VT_I8 || rightvt == VT_I8)
             resvt = VT_R8;
         else
             resvt = VT_R4;
     }
     else if (leftvt == VT_I8 || rightvt == VT_I8)
         resvt = VT_I8;
     else if (leftvt == VT_I4 || rightvt == VT_I4)
         resvt = VT_I4;
     else if (leftvt == VT_I2 || rightvt == VT_I2 ||
         leftvt == VT_BOOL || rightvt == VT_BOOL ||
         (leftvt == VT_EMPTY && rightvt == VT_EMPTY))
         resvt = VT_I2;
     else if (leftvt == VT_UI1 || rightvt == VT_UI1)
         resvt = VT_UI1;
     else
     {
         hres = DISP_E_TYPEMISMATCH;
         goto end;
     }
 
     /* coerce to the result type */
     if (leftvt == VT_BSTR && rightvt == VT_DATE)
         hres = VariantChangeType(&lv, left, 0, VT_R8);
     else
         hres = VariantChangeType(&lv, left, 0, resvt);
     if (hres != S_OK) goto end;
     if (leftvt == VT_DATE && rightvt == VT_BSTR)
         hres = VariantChangeType(&rv, right, 0, VT_R8);
     else
         hres = VariantChangeType(&rv, right, 0, resvt);
     if (hres != S_OK) goto end;
 
     /* do the math */
     V_VT(result) = resvt;
     switch (resvt)
     {
     case VT_NULL:
     break;
     case VT_DATE:
     V_DATE(result) = V_DATE(&lv) - V_DATE(&rv);
     break;
     case VT_CY:
     hres = VarCySub(V_CY(&lv), V_CY(&rv), &(V_CY(result)));
     break;
     case VT_R4:
     V_R4(result) = V_R4(&lv) - V_R4(&rv);
     break;
     case VT_I8:
     V_I8(result) = V_I8(&lv) - V_I8(&rv);
     break;
     case VT_I4:
     V_I4(result) = V_I4(&lv) - V_I4(&rv);
     break;
     case VT_I2:
     V_I2(result) = V_I2(&lv) - V_I2(&rv);
     break;
     case VT_UI1:
     V_UI1(result) = V_UI2(&lv) - V_UI1(&rv);
     break;
     case VT_R8:
     V_R8(result) = V_R8(&lv) - V_R8(&rv);
     break;
     case VT_DECIMAL:
     hres = VarDecSub(&(V_DECIMAL(&lv)), &(V_DECIMAL(&rv)), &(V_DECIMAL(result)));
     break;
     }
 
 end:
     VariantClear(&lv);
     VariantClear(&rv);
     VariantClear(&tempLeft);
     VariantClear(&tempRight);
     TRACE("returning 0x%8x %s\n", hres, debugstr_variant(result));
     return hres;
 }
srvaldez
Posts: 2640
Joined: Sep 25, 2005 21:54

Re: @Josep Roca, about Afx/CVar.inc

Postby srvaldez » Dec 13, 2020 0:45

hello Josep Roca
I copied the test from viewtopic.php?p=45580#p45580
but I personally think that supporting numeric string operations is not needed

Return to “General”

Who is online

Users browsing this forum: Dinosaur, SamL and 15 guests