none
VBScript: Dictionary object creating a key which never existed but present in another object RRS feed

  • Question

  • Hi,

    Below is a sample code in VBScript. I am providing three programming logics which are all the same but only one of them seems to be giving the correct result.

    Set a = CreateObject("Scripting.Dictionary")
    Set b = CreateObject("Scripting.Dictionary")
    
    a.add "oranges", 1
    a.add "apples", 1
    a.add "grapes", 1
    
    b.add "oranges", 1
    b.add "apples", 1
    
    ' ==================================================================
    ' Case 1. The below code shows that the dictionary
    ' object b contains the key "grapes" when it should not have
    ' ==================================================================
    For each x in a
      If a.exists(x) and a.item(x) > 0 and b.exists(x) and b.item(x) > 0 Then
        a.remove x
        b.remove x
      End If
    Next
    
    ' ================================================
    ' Case 2. The below code shows that the dictionary
    ' object b contains the key "grapes" when it should not have
    ' ================================================
    
    For each x in a
     If a.exists(x) and a.item(x) > 0 Then
      If b.exists(x) and b.item(x) > 0 Then
       a.remove x
       b.remove x
      End If
     End If
    Next
    
    ' ============================================
    ' Case 3. The below code works correctly. The logic is the same. Just that the If has been nested.
    ' ============================================
    
    For each x in a
     If a.exists(x) Then
      If a.item(x) > 0 Then
       If b.exists(x) Then
        If b.item(x) > 0 Then
         a.remove x
         b.remove x
        End If
      End If
     End If
    End If
    Next
    
    For each x in b
     msgbox x & ":" & b.item(x)
    Next
    
    Set b = nothing
    Set a = nothing
    
    
    

    The problem is that a Key is being created in the dictionary object "b" even though it was never added at all. However, as you see, it was added in the dictionary object "a".

    I tried this code on XP and Windows 7 and the behavior is the same. Can this bug be reported to Microsoft ?

    Thanks,
    Reju

    Wednesday, December 8, 2010 2:44 PM

Answers

  • Sorry, I misunderstood your problem. This code:

     Dim b
     Set b = CreateObject("Scripting.Dictionary")
     b.add "oranges", 1
     b.add "apples", 1
     WScript.Echo "b.Keys", Join( b.Keys, ", " )
     If b.item( "grapes" ) > 0 Then
       WScript.Echo "yes"
     Else
       WScript.Echo "no"
     End If
     WScript.Echo "b.Keys", Join( b.Keys, ", " )
     WScript.Echo "b(""grapes"")", TypeName( b( "grapes" ) )
    

    and the output:

    b.Keys oranges, apples
    no
    b.Keys oranges, apples, grapes
    b("grapes") Empty
    shows that VBScript adds the key "grapes" (with an empty value) to the dictionary to evaluate the boolean expression "b.item("grapes") > 0". This is not a bug, but a feature - called "autovivification"

    see: http://en.wikipedia.org/wiki/Autovivification

    Creating entries 'on need' is nice to have, if you - for example - need to count occurences as in:

     Dim b
     Set b = CreateObject("Scripting.Dictionary")
     Dim i
     For Each i In Array( 1, 2, 3, 2, 2 )
       b( i ) = b( i ) + 1
     Next
     For Each i In b.Keys
       WScript.Echo i, b( i )
     Next
     Exit Function
    

    output:

    1 1
    2 3
    3 1

    b( i ) = b( i ) + 1

    wouldn't work, if for the first occurrence of each number the second b(i) would be undefined.

    • Marked as answer by Reju George Wednesday, December 8, 2010 4:52 PM
    Wednesday, December 8, 2010 4:28 PM

All replies

  • I don't think that there is a bug. I modified your code (adding some diagnostics and removed the destructive .removes):

     Dim a, b, x
    
     Set a = CreateObject("Scripting.Dictionary")
     Set b = CreateObject("Scripting.Dictionary")
    
     a.add "oranges", 1
     a.add "apples", 1
     a.add "grapes", 1
     WScript.Echo "a.Keys", Join( a.Keys, ", " )
    
     b.add "oranges", 1
     b.add "apples", 1
     WScript.Echo "b.Keys", Join( b.Keys, ", " )
    
     WScript.Echo "b.Exists(""grapes"")", b.Exists("grapes")
    
    ' ==================================================================
    ' Case 1. The below code shows that the dictionary
    ' object b doesn't contain the key "grapes" as it should have
    ' ==================================================================
     For each x in a
       If a.exists(x) and a.item(x) > 0 and b.exists(x) and b.item(x) > 0 Then
    '   a.remove x
    '   b.remove x
       WScript.Echo 0, x
      End If
     Next
    
     For each x in a
       If a.exists(x) and a.item(x) > 0 Then
        If b.exists(x) and b.item(x) > 0 Then
    '     a.remove x
    '     b.remove x
          WScript.Echo 1, x
        End If
       End If
     Next
    
     For each x in a
      If a.exists(x) Then
        If a.item(x) > 0 Then
         If b.exists(x) Then
           If b.item(x) > 0 Then
    '        a.remove x
    '        b.remove x
            WScript.Echo 2, x
           End If
         End If
        End If
      End If
     Next
    
    

    The output:

    a.Keys oranges, apples, grapes
    b.Keys oranges, apples
    b.Exists("grapes") 0
    0 oranges
    0 apples
    1 oranges
    1 apples
    2 oranges
    2 apples

    proves that there are no grapes in b and all Ifs work as expected.

     

    Wednesday, December 8, 2010 3:09 PM
  • Hi Ekkehard,

         Firstly appreciate your taking time to respond... Let us look at just the case 1 for now... Why do you say there is a desctructive remove ?

    The condition is that if the key exists in both the dictionary objects and the item value is greater than 0, then delete the key from both the dictionary objects. I do need to remove them. What you are showing is just that its not present in the object "b" without removing. But thats not what I want.

     

    Thanks,

    Reju

    Wednesday, December 8, 2010 3:25 PM
  • Sorry, I misunderstood your problem. This code:

     Dim b
     Set b = CreateObject("Scripting.Dictionary")
     b.add "oranges", 1
     b.add "apples", 1
     WScript.Echo "b.Keys", Join( b.Keys, ", " )
     If b.item( "grapes" ) > 0 Then
       WScript.Echo "yes"
     Else
       WScript.Echo "no"
     End If
     WScript.Echo "b.Keys", Join( b.Keys, ", " )
     WScript.Echo "b(""grapes"")", TypeName( b( "grapes" ) )
    

    and the output:

    b.Keys oranges, apples
    no
    b.Keys oranges, apples, grapes
    b("grapes") Empty
    shows that VBScript adds the key "grapes" (with an empty value) to the dictionary to evaluate the boolean expression "b.item("grapes") > 0". This is not a bug, but a feature - called "autovivification"

    see: http://en.wikipedia.org/wiki/Autovivification

    Creating entries 'on need' is nice to have, if you - for example - need to count occurences as in:

     Dim b
     Set b = CreateObject("Scripting.Dictionary")
     Dim i
     For Each i In Array( 1, 2, 3, 2, 2 )
       b( i ) = b( i ) + 1
     Next
     For Each i In b.Keys
       WScript.Echo i, b( i )
     Next
     Exit Function
    

    output:

    1 1
    2 3
    3 1

    b( i ) = b( i ) + 1

    wouldn't work, if for the first occurrence of each number the second b(i) would be undefined.

    • Marked as answer by Reju George Wednesday, December 8, 2010 4:52 PM
    Wednesday, December 8, 2010 4:28 PM
  • Great. Autovivification was something new to me and it makes sense. Thanks Ekkehard for your time.

    Reju

    Wednesday, December 8, 2010 4:52 PM