Value Type Redux


 


I’d like to thank Yves Dolce for responding to Wesner Moise who writes:


 


Sender: Wesner Moise


 


re: Value Type Representation Between the Original and Revised C++


 


I am not sure that I understand you when you say v.ToString() results in an error, because v needs to be boxed in order to access an inherited method. V does not need to be boxed; indeed, valuetypes are not boxed in VB.NET or C#, when ToString() is called.


 


Yves dug a bit and wrote the following:


 


Sender: Yves Dolce


 


re: Value Type Representation Between the Original and Revised C++


 


I just tried with C#:


struct Complex


{


   public Complex( double r, double i )


   {


      this.r = r ;


      this.i = i ;


   }


   private double r, i ;


}


 



 


   Complex c = new Complex( 1, 2 ) ;


   c.ToString() ;


 


And the IL shows c IS boxed:


 


IL_000d:  ldloca.s   c


IL_000f:  ldc.r8     1.


IL_0018:  ldc.r8     2.


IL_0021:  call       instance void NeedToBox.Complex::.ctor(float64, float64)


IL_0026:  ldloc.0


IL_0027:  box        NeedToBox.Complex


IL_002c:  callvirt   instance string [mscorlib]System.ValueType::ToString()


 


In fact, if memory serves, this particular problem with value types and the contextual need to box them or not was at one time a problem with generics in C#, but I don’t recall the issue. As Yves further documents, in the original C++ with Managed Extensions release,


 


Sender: Yves Dolce


 


re: Value Type Representation Between the Original and Revised C++


 


Wesner,


 


Try calling ToString() on an instance of:


 


_value class Complex


{


   public:


      Complex( double r, double i ) : m_r(r), m_i(i) {}


 


 


   public:


      //virtual String * ToString() { return String::Format( S"{0} + {1} i", m_r.ToString(), m_i.ToString() ) ; }


 


   private:


      double m_r,


             m_i ;


} ;


 


I will fail with:


error C3610: ‘Complex’: value type must be ‘boxed’ before method ‘ToString’ can be called


 


As I wrote in my original blog entry,


 


The primary motive behind this design was pedagogical: it wished to make the underlying mechanism visible to the programmer so that she would understand the `cost’ of not providing an instance within her value type. Were V to contain an instance of ToString, the implicit boxing would not be necessary.


 


In thing2 [yes, referring to the two languages in this way is annoying, isn’t it?], the implicit boxing is carried out transparently:


 


            v.ToString(); // thing2


 


but at the cost of possibly encouraging the class designer to introduce an instance of ToString within V. The reason the implicit boxing is preferred is because while there is usually one class designer, there are an unlimited number of users, none of whom would have the freedom to modify V to eliminate the possibly onerous explicit box.


 


The other reason not to require the explicit boxing is that it requires the programmer to understand what is going on under the hood, and the C# and VB.NET design philosophy is not to burden the user with that level of complexity: not just the boxing that is required, but the use of a virtual table, and the need to locate the pointer for that table for value classes that do not provide an explicit instance, etc. That is a lot of baggage to ask the user to carry for a seemingly simple ToString() invocation!


 


This kind of dialogue is actually quite refreshing, and something that book-writing does not give rise to. Once again, let me thank Yves!


 


Comments (2)

  1. Jon Flanders says:

    I think it is always important to point out when having the "value types are boxed whenever they are treated as object" discussion, that if the value type overrides ToString() (or the method in question) boxing does not need to occur. Which is why it is important in C# and VB.NET to call ToString() explicitly on value types, because most of them *do* override ToString(), and doing it explicitly avoids the need to box. The compiliers (C#/VB.NET) add the box instruction if you just write Console.WriteLine(v);, where typing Console.WriteLine(v.ToString()); just ends up as a virutal method call). This is true even when the value type overrides ToString().

Skip to main content