Static Scope for Overloaded Methods

The manual states that Static variables only have scope within the method in which they are declared - but this doesn’t seem to be correct if the methods are overloaded.

Consider this call to these 2 methods:

Sub Pressed() Handles Pressed
  Dim r1 As String = m1.getItem("foo")
  System.DebugLog( r1)
  Dim r2 As String = m1.getItem(1)
  System.DebugLog( r2)
End Sub

Protected Function getItem(s as string) As String
  Static di As Dictionary
  If di = Nil Then
    di = New dictionary
    di.value("foo") = "fish"
  End If
  return di.Lookup(s, "nada")
End Function

Protected Function getItem(i as Integer) As string
  Static di As Dictionary
  If di = Nil Then
    di = New dictionary
    di.value(1) = "chips"
  End If
  Return di.Lookup(i, "nada")
End Function

I would expect the result to be “fish” and “chips”. But no, the result is “fish” and “nada”. Examining the content it seems the static di is shared between the two methods.

Interesting. I’m curious, what if you change the static variable name in the second function?

fish and chips of course. This is my work-around but I didn’t expect this result.

Make di.value(1) to be di.value(i) since 1 is not always the same datatype as i asn integer may be.

If this is shared amongst both methods that would seem to be a serious issue.

Yes, it would seem to be and it took a little while to discover what the problem was.

Noted, though this was just an example. In my case I have overloaded the same method over 20 times (using enumerations), each with about 10-20 dictionary entries - so now I have a big job to create a new name for each static - especially as find-change won’t find the right parts to change.

I can reproduce this with a Dictionary (and presumably any class), but not an integer, e.g., static di as integer = 1.

I think I’ve encountered this before without getting to the root cause, so this may have been the case for quite some time. If so, changing that behavior now could lead to breaking code, although I’d argue that it would actually fix already-broken code.

At the very least, this behavior should be documented. Have you filed Feedback?

1 Like

Not yet, but can do.

It seems it was documented previously <https://xojo.com/issue/52943> but has been “Archived” whatever that means.

New report…<https://xojo.com/issue/68073>

Does this change anything?

Haven’t tested, but the purpose of the previous structure was to create the dictionary only once on first use (lazy) rather than creating it every time the function is called. The proposed structure would create a new dictionary every time and defeat the point of using a Static.

Just to be clear, Derk’s proposal would still create the Dictionary only once within that function.

1 Like

Workaround

Protected Function getItem(i As Integer) As String
  Static di As New Dictionary
  
  If di.KeyCount = 0 Then
    di.value(1) = "chips"
  End If
  
  Return di.Lookup(i, "nada")
End Function

Protected Function getItem(s As String) As String
  Static di As New Dictionary
  
  If di.KeyCount = 0 Then
    di.value("foo") = "fish"
  End If
  
  Return di.Lookup(s, "nada")
End Function
1 Like

Yes, but then the dictionary entries are created every time - so same result as a Var.

This works. But why?

For some reason di is no longer Nil when you send the integer (after di = New Dictionary when the string is used) but still empty (KeyCount = 0).

Edit: as James mention in the next post, this “works” for first run, second getItem(“foo”) is using the other dictionary.

I take this back - something still wrong. Still picking up the wrong dictionary after the first run through.

If I run the following using Martin_T’s code I get:

Dim r1, r2 As String
Dim i As Integer = 1

r1 = m1.getItem("foo") 
System.DebugLog( r1)  //fish
r2 = m1.getItem(i) 
System.DebugLog( r2)  //chips
r1 = m1.getItem("foo") 
System.DebugLog( r1)  //nada
r2 = m1.getItem(i)  
System.DebugLog( r2) //chips

i.e. there is still confusion between the static instances of di.

1 Like

It means that it will be just ignored.