[Mono-devel-list] Performance w/ boxing

Jonathan Gilbert 2a5gjx302 at sneakemail.com
Sat Feb 21 15:10:45 EST 2004


At 09:24 PM 20/02/2004 -0500, you wrote:
>Below...
>
>On Fri, 2004-02-20 at 17:33, Jonathan Gilbert wrote:
[snip]
>> This isn't quite right. An 'out' parameter is in fact uninitialized and
>> does not carry any value at all.
>
>Not quite.  The value to which the parameter refers to is (can be)
>uninitialized.  The parameter itself is initialized to a well-known
>value.
[snip]
>> A 'ref' parameter must not be
>> uninitialized in the calling context when it is passed to the function, but
>> it may be initialized to 'null'.
>
>See above.  I'm referring to the pointer itself, not what the pointer
>refers to.  The pointer *cannot* be null in C#, but what the pointer
>refers to certainly can be null.

We are talking at different reference levels here :-) I am in fact very
familiar with C++ and have written several simple compilers, some of which
include support for arbitrary reference levels, just as C/C++ allow
arbitrary numbers of '*' in a pointer type. Yes, it is true that you
cannot, in C#, pass a reference which would result in a null pointer in the
underlying implementation :-)

[snip]
>> An 'object' can be checked for a boxed value type with the 'is' operator.
>> However, it isn't possible to restrict the type of the object that may be
>> boxed for a given call, not in C# or CIL, because it's impossible to tell
>> what an 'object' reference variable will refer to at compile time. 
>
>Indeed, but CIL does permit you to say "this is a managed pointer to
><some type/>, which could be null".  For example, managed C++ permits
>you to pass a boxed int directly to a function, and have the function
>accept a boxed int.
>
>What actually happens in Managed C++ is that you can get a managed
>pointer *into* a boxed int.  Syntax is similar to (from memory):
>
>	void Foo (int __gc* n);
>	int n = 42;
>	System::Object __gc* o = &n;
>	// this might need a different cast syntax; i can't remember
>	int __gc* pn = (int __gc*) o;
>	Foo (pn);
>
>The neat thing is that Managed C++ allows you to refer to the the
>integer *inside* the boxed integer, allowing cool things like that.  CIL
>permits it as well, but C# has no syntax to expose the functionality.
True, but this is still different from having a function which receives an
object reference that can only be a boxed int. The function in this case is
simply receiving a pointer to the integer value.

>> That
>> said, the function can always complain at runtime, which is about as good
>> as it gets.
> 
>Indeed.  For C#.

Well, that, or explicit boxing as I mentioned. The design that I presented
was aimed to solve the "can be null" problem, and you no doubt read Joshua
Tauberer's post which further addresses the performance issue.

Joshua Tauberer's struct, being a value type, is effectively no different
from using a separate 'bool' parameter to indicate whether the variable is
present, except that it wraps it up nicely into a single parameter.

void Foo(int value, bool value_is_actually_present)
{
  if (!value_is_actually_present) { ...}
  else { ... }
}

Of course, this is rather ugly. However, when there are a number of
integers, it can become useful to use a bitmapped flags parameter. Some
Win32 APIs work this way; the flags specify which parameters are actually
given meaningful values, and the information passed for other parameters is
ignored.

[Flags]
enum HasValue
{
  value1 = 1, value2 = 2, value3 = 4, value4 = 8,
}

void Foo(int value1, int value2, int value3, int value4, HasValue flags)
{
  if ((flags & HasValue.value1) == 0) { ... }
  else { ... }
  if ((flags & HasValue.value2) == 0) { ... }
  else { ... }
  /* etc. */
}

Jonathan




More information about the Mono-devel-list mailing list