2

In some legacy projects at my work, I see a lot of using statements referring to the dbContext:

using (myContext dal = new myContext())
{
    dal.DoSomeDatabaseThing
}

I believe this is fairly standard, and don't see a problem. In many places, however, I see something like this:

using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(...)
{
    sqlBulkCopy.DestinationTableName = myTable;
    sqlBulkCopy.BatchSize = 10000;
}

Lo these many years, I've understood that the object referenced in a using statement is immutable. Indeed, MSDN docs state, "Within the using block, the object is read-only and cannot be modified or reassigned." Nevertheless, code blocks like the one above seem to work just fine.

What am I missing here? Clearly assigning values to an object's properties is modifying the object, no? I spoke to the team lead but he seemed unconcerned -- if it ain't broke, don't fix it -- kind of thing. But, it grates on me!

Any thoughts? Thanks

EoRaptor013
  • 1,735
  • 4
  • 18
  • 31
  • 2
    It's immutable as in you can't reallocate its memory.You can't say `SqlBulkCopy copy=new ....`.You can however alter its fields.Basically think of it as a cursor to some chunk of memory.While you can't put the cursor on another chunk, you are allowed to do anything you want in your `chunk`. – Bercovici Adrian Apr 11 '19 at 19:25
  • 3
    The object reference can't be changed. Its properties can. Similar to having a `readonly` list - the list can't be changed but its contents can. – Yuck Apr 11 '19 at 19:25
  • Its not in the documentation anymore, well not the version i am looking at – TheGeneral Apr 11 '19 at 19:27
  • 2
    This is a pointer under the hood. What is being pointed to can't change. What it points at can. – Hogan Apr 11 '19 at 19:27
  • It now says *'Within the using block, the object is read-only and cannot be modified or reassigned.'* which is a much better way to say it than immutable – TheGeneral Apr 11 '19 at 19:27
  • You can't change the reference. In other words you cannot change the value stored in the variable _sqlBulkCopy_. – Steve Apr 11 '19 at 19:28
  • 1
    I think immutable was the wrong word to use, anything can implemented the `IDisposable` pattern and these classes can `Mutate` (in the most common definition we use). immutable has nothing to do with references its about self constancy of an object whose state cannot be modified after it is created.. So i think the documentation wasn't as concise as it should have been.. also note in the version of the documentation i can see immutable has been removed – TheGeneral Apr 11 '19 at 19:36
  • _Clearly assigning values to an object's properties is modifying the object_ Nope, it is modifying the fields. – TaW Apr 11 '19 at 19:37
  • The wording here is definitely confusing. Note that the C# specification only ever talks about the local variables. It states "Local variables declared in a resource_acquisition are read-only, and must include an initializer" (Here resource_acquisition is `SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(...)`) This is much more precise. It is obvious that the objects are not immutable. FileStream has private fields to track position and internal buffers that are modified within a using block, for example. – Mike Zboray Apr 11 '19 at 19:41
  • 2
    "read-only" values behave consistently between `readonly` fields and `using` statement so - value can't be modified but properties/fields can be changed... Not sure why doc written as "the object … cannot be modified" (maybe tried to oversimplify the constraints) – Alexei Levenkov Apr 11 '19 at 20:30
  • @AlexeiLevenkov I agree, i think the documentor was alluding to the *using* statement as the conceptual unit of immutability, even then its still a suspect statement in the common vernacular – TheGeneral Apr 11 '19 at 20:36

3 Answers3

4

The specification has this to say about the readonly-ness of the resource acquired in a using statement:

Local variables declared in a resource-acquisition are read-only, and must include an initializer. A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the ++ and -- operators), take the address of them, or pass them as ref or out parameters.

Of note, and as pointed out in the comments, this pertains to the local variable itself, and not the object that it references, which a using statement likely couldn't make immutable in and of itself without going to some extremes.

Suppose your IDisposable has a method that, when called, increments a private field to keep track of usages before disposal. The object is clearly mutable, but the mutation is hidden as a side-effect. Should a using attempt to prevent that? I strongly doubt it. Immutability is not especially easy to achieve in C#, the type must be designed with being immutable in mind. Even marking a field readonly only effects the field variable- reference types could still be modified through method calls and setting fields or properties.

Jonathon Chase
  • 9,396
  • 21
  • 39
  • 1
    They didn't want to achieve immutability, they just wanted to stop the variable from being reassigned, which is why the choice of words was clearly suspect – TheGeneral Apr 11 '19 at 19:49
  • Thank you for the info. I must admit that the word immutable came from me, not from the documentation. I was trying to abbreviate the language from the documentation that I then quoted anyway. The notion that a method can modify internal variables makes clear to me what's going on. I DO think the documentation could use some improvement. – EoRaptor013 Apr 12 '19 at 00:00
2

The statement that object is immutable inside the using block is bit misleading because actually it implies that the variable is immutable. That is you cannot do a reassignemt of the variable to another instance:

using (var a = new A())
{
    a = new A(); // compilation error
}

but it's still permitted to mutate the instance

using (var a = new A())
{
    a.Prop = someValue;
}

The reasoning is obvious. The purpose of the using statement to ensure that an instance is disposed exactly at the moment you specified, and a reassignment would negate this, while internal state mutation has no influence on this.

Dmytro Mukalov
  • 1,949
  • 1
  • 9
  • 14
-3

I think you are interpreting USING in wrong way, USING just ensures the boundary of the objects declared in them, once the compiler passes by this statement the object are destroyed automatically, thus releasing the memory before GC comes in play.

(Assigning values, referencing would be okay in such case.)

Some references here: What are the uses of "using" in C#

Good Luck.

foo-baar
  • 1,076
  • 3
  • 17
  • 42
  • Im sure OP knows how to use a using statement, and has a good understanding of how they work, the question was around the phrasing of the documentation IMO – TheGeneral Apr 11 '19 at 19:31
  • This doesn't answer the question at all. – Yuck Apr 11 '19 at 19:32