locked
Strange behavior of if condition RRS feed

  • Question

  • Doesanyone can tell mewhy this code does not make me out of my sub...

    If Prenom_tb.Text.Trim Is String.Empty Then
         Exit Sub
    End If

    When in my execution window I get this result

    ? Prenom_tb.Text.Trim Is String.Empty
    True

    However, with this code I leave the sub

    If Prenom_tb.Text.Trim = String.Empty Then
         Exit Sub
    End If

    Thanks,

    Thursday, March 8, 2012 8:51 AM

Answers

  • dont use "Is" with strings

    The CLR is using what is called the Intern Pool to store the values of the strings

    In this process, is two strings are equals, the CLR will not put in memory two copy of the same strings, instead, it will set the 2 string objects to the same reference, a single copy of the string literal in memory.

    However, depending from where the string is coming from, the process of setting the two object to the same reference may not be done immediatly, or may not be done at all.

    And to make this even more difficult, different version of the Framework does have different behaviour about this.

    so, if a string "IS" another string, is something that is very difficult to predict, something that will not follow the logic of your program and something that may change from computer to computer depending on the framework version installed

    • Proposed as answer by Cor Ligthert Thursday, March 8, 2012 1:12 PM
    • Marked as answer by Youen Zen Friday, March 16, 2012 8:19 AM
    Thursday, March 8, 2012 11:26 AM

All replies

  • The IS test if the objects are the same.

    The = test the content.

    Success
    Cor



    • Edited by Cor Ligthert Thursday, March 8, 2012 10:05 AM if objects are the same
    Thursday, March 8, 2012 9:14 AM
  • Ok but the following condition is 'true' so why it doesn't exit the sub?

    Prenom_tb.Text.Trim Is String.Empty
    If Prenom_tb.Text.Trim Is String.Empty Then
         Exit Sub
    End If

    Thx

    Thursday, March 8, 2012 9:43 AM
  • Changed my reply.

    IS is the case if it is about the same objects for types is the ISTypeOf 

    What does execution window mean?

    I get false


    Success
    Cor


    Thursday, March 8, 2012 10:06 AM
  • When I execute the code in debug mode, the condition's result is 'True'.

    There is nothing in my TextBox control.

    It does not exit the sub.

    Thursday, March 8, 2012 10:09 AM
  • Strange for me it is false if I test your code, so tell where it is True?

    Success
    Cor

    Thursday, March 8, 2012 10:19 AM
  • After F10:

    Thursday, March 8, 2012 10:27 AM

  • Success
    Cor

    Thursday, March 8, 2012 11:00 AM
  • The test returns True. Both expressions are type String.

    Thursday, March 8, 2012 11:19 AM
  • dont use "Is" with strings

    The CLR is using what is called the Intern Pool to store the values of the strings

    In this process, is two strings are equals, the CLR will not put in memory two copy of the same strings, instead, it will set the 2 string objects to the same reference, a single copy of the string literal in memory.

    However, depending from where the string is coming from, the process of setting the two object to the same reference may not be done immediatly, or may not be done at all.

    And to make this even more difficult, different version of the Framework does have different behaviour about this.

    so, if a string "IS" another string, is something that is very difficult to predict, something that will not follow the logic of your program and something that may change from computer to computer depending on the framework version installed

    • Proposed as answer by Cor Ligthert Thursday, March 8, 2012 1:12 PM
    • Marked as answer by Youen Zen Friday, March 16, 2012 8:19 AM
    Thursday, March 8, 2012 11:26 AM
  • It is possible to demonstrate the inconsistency between the run-time and the immediate evaluation of the expression:

    • Edited by Acamar Thursday, March 8, 2012 10:28 PM Image corrected.
    Thursday, March 8, 2012 8:50 PM
  • And after executing the assignment? :)

    Armin

    Thursday, March 8, 2012 10:00 PM
  • And after executing the assignment? :)

    The same!  Which is fortunate because if it wasn't then I would have absolutely no explanation for the oddity.

    I have fixed the image. 

    Thursday, March 8, 2012 10:24 PM
  • That's really strange - and interesting.

    I've played a bit with it... You can even fool it by adding the expression

          TextBox1.Text Is String.Empty & "abc".Substring(0,0)

    to the watch window. Guess what it says... TRUE.   lol    The references can never be equal.


    Armin

    Thursday, March 8, 2012 10:57 PM
  • If the intern pool is slightly out of step with the code (as CrazyPennie suggests) then it is possible that the runtime comparison detects two strings as not referring to the same object, while the immediate or watch comparison occurs only after the intern pool has been brought up to date, and the result will be True.  That's the 'explanation' I referred to.  I'm not entirely convinced, but it sounds plausible.

    The problem is that the oddity only occurs with empty strings: the intern table appears to be up to date for any use of Is with a non-empty string, even when the values are literals or expressions
            Dim B As Boolean = "ABC" Is "A" & "B" & "C"

    So it's really an issue of empty strings and Nothing.  This comment probably explains it, although i can't see the exact connection:
    "In the .NET Framework version 3.5 Service Pack 1, the Intern method reverts to its behavior in the .NET Framework version 1.0 and .NET Framework version 1.1 with regard to interning the empty string. In the following example, the variable str1 is assigned a reference to Empty, and the variable str2 is assigned the reference to Empty that is returned by calling the Intern method after converting a StringBuilder object whose value is Empty to a string. Then the references contained in str1 and str2 are compared for equality. "
    http://msdn.microsoft.com/en-us/library/system.string.intern.aspx

    Thursday, March 8, 2012 11:53 PM
  • Crazy is exactly right (been there, done that).

    Test it using a math expression:

    If Prenom_tb.Text.Trim <> "" Then
          ' Whatever
    End If

    Friday, March 9, 2012 12:36 AM
  • As additional information (this doesn't say a lot but here it is), check out this MSDN document. The following pretty well sums it up though:

    "Because you're actually comparing ANSI values when you compare two strings, you can use the same comparison operators that you would use with numeric expressions — greater than (>), less than (<), equal to (=), and so on. In addition to these numeric comparison operators, you can use the Like operator, which is specifically for use in comparing strings, including strings that contain wildcard characters."

    Friday, March 9, 2012 12:45 AM
  • I'd say that (nothing IsNot string.empty)

    Option Strict On
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            Dim a As String
    
            If a Is String.Empty Then
                Stop
            End If
    
            a = String.Empty
    
            If a Is String.Empty Then
                Stop
            End If
    
            'any how I'd do it like this
            If String.IsNullOrWhiteSpace(a) Then
    
            End If
        End Sub
    End Class

    • Edited by TechNoHick Friday, March 9, 2012 2:24 AM
    Friday, March 9, 2012 2:19 AM
  • That's really strange - and interesting.

    I've played a bit with it... You can even fool it by adding the expression

          TextBox1.Text Is String.Empty & "abc".Substring(0,0)

    to the watch window. Guess what it says... TRUE.   lol    The references can never be equal.


    Armin

    Armin,

    I see that I was testing the property and not the method. With the method I get also this.

    Your interest is more than mine in this area (using Is is simply wrong for this expression so why investigate what gives this result).

    However, if I had the same intention to investigate this kind of things like you, I would look if the String (a shared object) returns an object in his method. Probably it uses for all tests the same object, so all methods return the same shared object and therefore the IS is the same. 

    But I'm not interested to test that, maybe you?

    However, probably only in the immediate window, in the code the expression returns false.

    :-)


    Success
    Cor


    Friday, March 9, 2012 10:52 AM
  • If the intern pool is slightly out of step with the code (as CrazyPennie suggests) then it is possible that the runtime comparison detects two strings as not referring to the same object, while the immediate or watch comparison occurs only after the intern pool has been brought up to date, and the result will be True.  That's the 'explanation' I referred to.  I'm not entirely convinced, but it sounds plausible.

    The problem is that the oddity only occurs with empty strings: the intern table appears to be up to date for any use of Is with a non-empty string, even when the values are literals or expressions
            Dim B As Boolean = "ABC" Is "A" & "B" & "C"

    So it's really an issue of empty strings and Nothing.  This comment probably explains it, although i can't see the exact connection: [...]

    I'm not sure if I can follow:

    • The line

           Dim B As Boolean = "ABC" Is "A" & "B" & "C"

      is equal to

           Dim B As Boolean = "ABC" Is "ABC"

      because the compiler already concatenates string literals. As the runtime interns all String literals, B is True in this case, but that's no surprise. Or is that's what you're saying? Just asking. :-)

    • About the intern pool being up to date: (I know you're also guessing like we all currently do. :-D )
      As long as String.Intern function isn't called, only literals are interned automatically. That would mean, that all results of String expressions in the watch window are always passed to String.Intern by the IDE. However, I wouldn't know why it should do so.


    My guess (tonight) was that the IDE mixes up the "Is" operator with the "Is" keyword used in "Case Is ..." in a Select Case statement. That would mean it's not a comparison of references but like a "=" comparison. It would explain why the watch window shows "True". So I've add this to the watch window:

          TextBox1.Text IsNot String.Empty    FALSE

    Using "IsNot", I can be sure that references are compared.

    Another expression in the watch window:

          Object.ReferenceEquals(TextBox1.Text, String.Empty)    TRUE

    That's surprising and still without an explanation. Even less explainable if you do this:

          Dim s1, s2 As String
          s1 = TextBox1.Text
          s2 = TextBox1.Text
          Dim b3 = s1 Is s2        FALSE

    So, the Text property obviously returns a different (new) String each time.



    Armin

    Friday, March 9, 2012 11:47 AM
  • However, if I had the same intention to investigate this kind of things like you, I would look if the String (a shared object) returns an object in his method. Probably it uses for all tests the same object, so all methods return the same shared object and therefore the IS is the same. 

    But I'm not interested to test that, maybe you?

    Hi Cor,

    Hmm.... I can't catch it. I would test it if your intention would reach my today tired brain... :) I mean, what kind of shared object? And "returns an object".. sure, if it's not Nothing it's always an object. But I got it wrong probably.


    Armin

    Friday, March 9, 2012 11:54 AM

  • Hi Cor,

    Hmm.... I can't catch it. I would test it if your intention would reach my today tired brain... :) I mean, what kind of shared object? And "returns an object".. sure, if it's not Nothing it's always an object. But I got it wrong probably.


    Armin

    Armin,

    I mean something like this, and I can tell you that the result of this method is definitaly not the case.

    Public Class Form1
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            If X.Armin Is X.Cor Then
                MessageBox.Show("We Are Equal")
            End If
        End Sub
    End Class
    Public Class X
        Public Shared result As resultClass
        Public Shared Function Armin() As resultClass
            resultClass.y = "Armin"
        End Function
        Public Shared Function Cor() As resultClass
            resultClass.y = "Cor"
        End Function
        Public Class resultClass
            Public Shared Property y As String
        End Class
    End Class
    

    :-)


    Success
    Cor

    Friday, March 9, 2012 12:36 PM
  • I mean something like this, and I can tell you that the result of this method is definitaly not the case.
    [Code]

    LOL, nice code (when stepping through)! And it makes such a lot of sense. 

    Armin

    Friday, March 9, 2012 12:43 PM
  • Sorry to step in a thread at the end of its life.  I just wanted to add that my first instinct when testing for an empty string resulting from UI content is to use either String.IsNullOrEmpty(Prenom_tb.Text.Trim) or else String.IsNullOrWhiteSpace(Prenom_tb.Text) when using the 4.0 framework.  Yes, I know it can't be null but I prefer to delegate the logic to a framework method.
    Friday, March 9, 2012 2:14 PM