For Each bug when looping over a Dictionary

Hi there

Using Xojo 2023r1, why would this code not yield an error during Compile time?

Var myDict As New Dictionary

myDict.Value("de") = "Deutsch"
myDict.Value("en") = "English"
myDict.Value("fr") = "Français"

For Each key As String In myDict
  ListBox1.AddRow myDict.Value(key).StringValue
Next

As you may have spotted, I accidentally looped over a Dictionary (instead of using its Keys method).

A Dictionary is neither a String array not does it implement the Iterable interface. In my opinion, this should yield a “This object does not implement the Iterable interface and cannot be used in a For Each loop” error during compile time.

Do I overlook something here?

Well… You stumbled on something, but not what you think

Dictionaries are iteratable BUT their items aren’t strings, they are DictionaryEntry objects

In your example the compiler should point out the incompatibility in the “key” declaration as String instead of the expected DictionaryEntry. Compiling it and raising a crazy exception later is an issue needing a report.

Var myDict As New Dictionary

myDict.Value("de") = "Deutsch"
myDict.Value("en") = "English"
myDict.Value("fr") = "Français"

For Each entry As DictionaryEntry In myDict
  System.DebugLog entry.Value
Next

---

Run:
08:28:10 : test Launched
08:28:11 : Deutsch
           English
           Français
1 Like

Well, thank you Rick!

Then I correct my assumption in that Xojo should yield a “Type mismatch” compile time error, since a DictionaryEntry (which I didn’t even realize existed) is not assignable to a String.

I’m a little sad that, given the Documentation and the lack of a compile-time error (and since I was working inside a web app, I didn’t even see the Runtime error which made me spend a lot of time bug hunting), I was not able to infer that.

The documentation is unsurprisingly bad regarding this feature:

  1. In “For Each … Next” there is no mention and no example at all.

  2. In “Iterable

image

  1. In “Dictionary”:

There I found an actually working example under the “Value”(?) method:

image

I might open a bug so this part of the documentation can be improved. Thank you again, Rick, for your fast response.

1 Like

The docs are always needing improvements. There are lots of hidden features that could be better documented, sometimes in more than one place as a cross-reference citation.

Can’t the key be a Variant? Seems to me the loop would work until a non-string key is encountered (untested). Thus, not detectable at compile time.

The Key is a Variant, yes, but the iterable items of a dictionary are DictionaryEntries. You can of course iterate over the array of keys as well.

1 Like

It’s a different construct using keys, they can for sure be variants, but it’s unnecessary and less performant then directly using strings if the keys are strings:

Var myDict As New Dictionary

myDict.Value("de") = "Deutsch"
myDict.Value("en") = "English"
myDict.Value("fr") = "Français"

For Each key As String In myDict.Keys
  System.DebugLog key + " : " + myDict.Value(key)
Next

System.DebugLog "---"

For Each entry As DictionaryEntry In myDict
  System.DebugLog entry.Key  + " : " + entry.Value
Next
1 Like