Make immutable objects mutable

In .Net the String object is an immutable object, which means that it’s basically constant and can’t be changed. You can’t change a string, you can only create new strings. The various methods that the String class have never directly change the string they operate on, instead they return a new string.

Dim myString As String = "Hello World"
Dim mySecondString As String = myString.Substring(0, 5)
Console.WriteLine(myString) 'Hello World
Console.WriteLine(mySecondString) 'Hello


Even though we developers modify strings all the time, which can make them look mutable, they aren’t. What happens is that a new string is created and the reference variable we use simply points to the new string on the heap.



Make the string mutable



OK, the title of this article isn’t really true since you can’t make a string mutable, however because of a strange behavior in the VB implementation of extension methods, you can make it appear as if it was. Note that this is only possible in VB, to the best of my knowledge, C# does not have this behavior. This little known fact is that the argument of the extension method, the first parameter, can be passed by reference. Have a look at this example code:



<Extension()> _
Public Sub MutableInsert(ByRef str As String, _
                         ByVal position As Integer, _
                         ByVal text As String)
  If position >= str.Length Then
    str = str & text
  ElseIf position <= 0 Then
    str = text & str
  Else
    str = str.Substring(0, position) & text & str.Substring(position)
  End If
End Sub

Public Sub Main()
  Dim myString As String = "Hello world"
  myString.MutableInsert(5, " cruel")
  Console.WriteLine(myString) 'Hello cruel world
End Sub



Being a .Net developer for many years, this behavior looks weird to me. The fact that something that appears as an instance method actually can change the instance itself. But in some occasions it could actually be pretty useful. Take the following code as an example:



<Extension()> _
Public Sub EnsureNotNull(ByRef str As String)
  If str Is Nothing Then
    str = String.Empty
  End If
End Sub

Public Sub ChangeString(ByVal str As String)
  str.EnsureNotNull()
  Console.WriteLine("str Is Nothing = {0}", str Is Nothing) 'False
End Sub

Public Sub Main()
  ChangeString(Nothing)
End Sub


Personally I’m not sure that this feature is a good thing. If I can change a string from Nothing (or null) to String.Empty what stops me from doing the opposite? Well, absolutely nothing (no pun intended).



<Extension()> _
Public Sub EvilMethod(ByRef str As String)
  str = Nothing
End Sub

Public Sub Main()
  Dim msg As String = "Hello world"
  msg.EvilMethod()
  Dim newMsg As String = msg.Substring(0, 5) 'throws a NullReferenceException
  Console.WriteLine(newMsg)
End Sub


There you have it, the evil programmer have struck again.



Have fun.

5 thoughts on “Make immutable objects mutable”

  1. Hello Sani,

    You are correct that you can’t call the extension method from C#. Or at least you can’t use it as an extension method but you can still call it as if it was a regular static method.

    string s = null;
    MyNamespace.EnsureNotNull(ref s);

  2. Well, as I have stated in the article, I’m not sure this feature is a good thing. However there might be times when this actually could be quite nifty, especially when you’re dealing with mutable objects. In Dev10 there is a new System.Threading.SpinLock structure that provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop repeatedly checking until the lock becomes available. It could be valuable to add the following extesion method to a SpinLock.

    Public Sub Execute(ByRef lock As Threading.ThreadLock, ByVal action As Action)
    Dim locked As Boolean
    Try
    lock.Enter(locked)
    action()
    Finally
    If locked Then lock.Exit()
    End Try
    End Sub

  3. I understand your point.

    However I’m not so keen on adding an Execute Extension Method on SpinLock.
    To me it seems like SpinLock is executing the Action, which it isn’t.
    The above example doesn’t execute the action on the SpinLock object.
    I would differentiate objects and behaviour.

    I see Extension Methods as methods extending the objects behaviour. Not the behaviour of the application.

    But that’s just me. I can’t speak for others. :)

    All in all I don’t see the necessity to use ByRef Extension Methods at all.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>