Apache OpenOffice (AOO) Bugzilla – Full Text Issue Listing |
Summary: | IIF is fragile in StarBasic | ||||||||
---|---|---|---|---|---|---|---|---|---|
Product: | General | Reporter: | andrew | ||||||
Component: | scripting | Assignee: | ab | ||||||
Status: | RESOLVED FIXED | QA Contact: | |||||||
Severity: | Trivial | ||||||||
Priority: | P3 | CC: | biczoa, hanya.runo, issues, johann.alfred.schmidt, marcelly.bernard, ms777, rado | ||||||
Version: | OOo 2.0.2 | ||||||||
Target Milestone: | 4.2.0 | ||||||||
Hardware: | All | ||||||||
OS: | All | ||||||||
URL: | http://www.oooforum.org/forum/viewtopic.phtml?t=33910 | ||||||||
Issue Type: | DEFECT | Latest Confirmation in: | --- | ||||||
Developer Difficulty: | --- | ||||||||
Attachments: |
|
Description
andrew
2006-03-25 13:14:52 UTC
np->ab reassign Complicated example, has to be evaluated, STARTED, OOo Later for now I have created a somewhat simplier test case - see below. Tested with OO 2.1.0 on Win XP SP2 1.) Put the code into an empty calc doc 2.) Run the code from Basic IDE: no error 3.) Change "Sub Test11" to "Sub Test1" 4.) Run again - it fails in the indicated line Hope that helps a bit, ms777 Sub Test11 Dim lTest as Long lTest = 1 Dim x as Long x = IIF(lTest=1,0,23) x = IIF(lTest=0,0,23) Dim y as String msgbox IIF(lTest=0,"Hello","GoodBye") msgbox IIF(lTest=1,"Hello","GoodBye") 'after modification fails with "Inadmissable value or data type. Data type mismatch" ! x = IIF(lTest=1,0,23) End Sub Here is ms7777's shorter test case stripped down to extremes, still producing the same error message after running, editing and running it again (sorry, I did not work through pitonyak's long test case). Sub Test11 IIf(true, 0.0, "") IIf(true, 0, "") End Sub Remarks to stripping down: 1) It is not necessary to change the name of the sub, inserting a line break will do just as well. 2) The first argument of the IIf (ie the condition) does not have to be a variable to reproduce the error. 3) IIf works without using its return value. 4) If the first argument evaluates to true, the third argument does not seem to interfere with the error, only the second argument counts. 5) The exact type of the arguments does not matter, the only thing required is that the second arguments differ in type. 6) Run ms7777's code once, edit it, then run it again and again, the error will occure at different rows! I found that in order to reproduce this oscillation effect, at least 4 IIfs are needed: Sub Test11 IIF(true, 0, "") IIF(true, 0.0, "") IIF(true, 0.0, "") IIF(true, 0, "") End Sub I can organize and send further interesting test cases I have found if it helps solving this issue. Tested all four macros (testCalcFunctions and the 3 versions of Test11) in OOo 3.0 only to reproduce the same behavior. Additional hints to reproduce exactly the same behavior: Be sure to a) use a new Calc document before running each macro for the first time OR b) save it, close it and open it again (OOo does not have to be closed). If you 1) test and delete one macro, then 2) paste and test another, you may get different results. Another example, in the hope that some developer tackles the problem... Option Explicit Sub Main Dim g as double g = 0 print g, SkipZero(g) print g, SkipZero(g) End Sub function SkipZero(grandeur As Double) As Double SkipZero = IIF(grandeur=0 , 1, grandeur) end function Run the macro Main, the first call to SkipZero is OK but the second call throws error "Inconsistent type of data" at the line with the IIF instruction. If the bug does not appear, change the value of g to 1 and run again. Then change the value back to 0 and run again, it will appear. Once triggered, the error can also appear during evaluation of a cell formula calling SkipZero. I can reproduce the bug on Windows XP with OOo 3.0.0, 2.4.2RC1, 1.1.5 If this instruction cannot be corrected it would be fair to document it as "discontinued, do not use" in the help (F1). I had the error using: Iif(sVar = "", "", ", ") In my code, sVar is not empty most of the time (condition FALSE). The behavior seamed random on several runs. Note on the comment of hba : I do expect Iif to produce an error if arguments #2 and #3 are not of the same type, since Iif is a function and thus should have a fixed return type, no matter the valuation of #1. It's perfectly fine that Iif(TRUE, 0, "") produces an error. The point of the this issue is that Iif sometimes (more or less unpredictably) produces an error, *even though* the types of #2 and #3 do match. If the function cannot be fixed, it really should be removed. After all it can be easily worked around, and the random errors are a time bomb for the developers. The problem is still there in OOO 3.2. And it was already there in OOO 2.0.1 (see http://de.narkive.com/2006/1/9/559733-ooo-2-0-1-iif.html) I also think, Iif sould be removed, if it cannot be fixed... Maybe as a first step one can easily add a hint, that this function is depreciated to that error message of Iif (in German: "Unzulässiger Wert oder Datentyp Datentypen unverträglich") This helps already to understand, what's going on. The random occurence of that message is a mess. Best regards kunkunuzzi Problem is still there. OOO 3.3.0 (9567) Mac. So I've built my own func: '----------------------------------------------------------------- ' Replacement for iif (very unreliable) '----------------------------------------------------------------- Function ifif(bBool as Boolean, sTrue as String, sFalse as String) If bBool then ifif = sTrue Else ifif = sFalse End If End Function *** Issue 125953 has been marked as a duplicate of this issue. *** I found the strange difference among the following in disassembled optree. - Original Sub Main IIf(true, 1.0, "") End Sub -- Disassembled Position Op Op1 Op2 OpStr ----------------------------------------- 00000000 Lbl00000000: 00000000 45 00000000 JUMP Lbl0000 // Label ; Sub Main 00000005 Main: 00000005 87 00000003 00000000 STMNT 3,0 (For-Level: 0) ; IIf(true, 1.0, "") 0000000E 87 00000004 00000000 STMNT 4,0 (For-Level: 0) 00000017 18 ARGC // new argv 00000018 80 00000002 0000000C RTL true ; Variant 00000021 19 ARGV 00000022 40 00000004 NUMBER "1" 00000027 19 ARGV 00000028 41 00000005 STRING "" 0000002D 19 ARGV 0000002E 80 00008003 00000000 RTL IIf ; Empty, Args 00000037 1C GET ; End Sub 00000038 87 00000005 00000000 STMNT 5,0 (For-Level: 0) 00000041 2B LEAVE Execute the code above in the Basic IDE and then change like the following. - Second argument is modified Sub Main IIf(true, "", "") End Sub Execute the code to be compiled -> error. -- Disassembled Only position 2E shows important difference from the original. Position Op Op1 Op2 OpStr ----------------------------------------- 0000002E 80 00008003 00000002 RTL IIf ; Integer, Args Op2 is type information. It was changed from Empty to Integer. - After restarting the office The same code above gave correct opcode. 0000002E 80 00008003 00000000 RTL IIf ; Empty, Args The wrong Op2 code gives the error message because impossible to assign the value. Type miss match between desired type and real return value from the function call. The parser tries to find the information of the function that called by _RTL pcode from the runtime library in SbiParser::CheckRTLForSym function. At first compilation of the code, the runtime library does not have any information about Iif function and its entry is created as SbxMethod instance and stored in SbxObject::pMethods array, see SbiStdObject::Find function. The runtime library is not cleared before the second compilation after the modification of the code. At first execution of the code, the SbxMethod instance created at the compilation is used to call Iif function. The type of return value is set at first execution of the runtime function. Iif is defined as RTLFUNC(Iif) (SbRtl_Iif function is generated by the macro) in basic/source/runtime/methods1.cxx file. If Iif is called like: Iif(true, 1, ""), the return type is going to be SbxINTEGER from the second argument in *rPar.Get(0) = *rPar.Get(2); line of the runtime funtion. In SbxValue::operator= function called at assignment of the return value, last Put method call set the type of return value of the function. SbxMethod::aData (declared in parent SbxValue class) instance variable is used to keep return value from the runtime function and its eType element is used to get its value type. Changes of SbxMethod::aData.eType - first compilation: SbxEMPTY as shown in disassembled code, this match with the function definition in basic/source/runtime/stdobj.cxx file - first execution: depends on the condition and return value of Iif function - second compilation: depends on the result of the last call of Iif function At the second compilation, SbxMethod instance for Iif function having the last value of the function call, is used to obtain the function information. The compilation result is unstable like described in the Comment 11. Return value of most runtime functions are always same type, so this problem revealed on Iif function since its return type can be changed by the coder. I could reproduce the same problem with Choose runtime function by the procedure written in Comment 11. - Original: Sub Main Choose(1, 1, 2) End Sub 0000002A 80 00008002 00000000 RTL Choose ; Empty, Args - Changed: Sub Main Choose(1, "", 2) End Sub 0000002A 80 00008002 00000002 RTL Choose ; Integer, Args The OpCode2 for the type is wrong for the second code. Created attachment 84305 [details]
Proposed patch to use defined return type for pre-defined runtime functions
Add the way to know a SbxMethod instance is dedicated to pre-defined runtime function
and use its information at compilation for RTL operation code.
Fixed on trunk, revision 1650325 Created attachment 85090 [details]
Document contains macro to confirm this fix
To confirm this fix, open the attached document which contains Basic macro.
- Choose Tools - Macros - Organize Macros - OpenOffice Basic...
- Choose i63614_iif.odt/Standard/Module1 in Macro from tree on the dialog
- Click "Edit" button on the dialog to show the Basic IDE
- See below or the code for the additonal procedure to confirm.
Sub Main
' To confirm,
' 1. execute this code
' 2. change the part of the code according to the following
' 3. click "Step Over" button several times on the toolbar
' -> no "Data type mismatch." dialog should be shown
'
msgbox IIf(false, "", 1)
' To confirm, change
' from IIf(true, 1.0, "")
' to IIf(true, "", "")
Choose(1, 1, 2)
' To confirm, change
' from Choose(1, 1, 2)
' to Choose(1, "", 2)
End Sub
|