[Mono-devel-list] Performance w/ boxing

Jonathan Pryor jonpryor at vt.edu
Fri Feb 20 21:24:31 EST 2004


Below...

On Fri, 2004-02-20 at 17:33, Jonathan Gilbert wrote:
> At 07:36 AM 20/02/2004 -0500, Jonathan Pryor jonpryor-at-vt.edu |mono-list
> subscription| wrote:
<snip/>
> >That's not quite what the original poster (Jaroslaw Kowalski) wanted. 
> >He wanted a way to check for either (a) null, or (b) a boxed integer.  A
> >"ref" or "out" integer can never be null.
> 
> 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.

The best way to think of this is to use C++. :-)

The original poster wanted to be able to use a pointer, so that null (no
object) could be passed:

	void function (int* value) {/* ... */}

"Safe" C# does not permit that.  (You can always insert a few unsafe
keywords and use raw pointers, but we're avoiding that for now.)  In C#
(and probably the CLS), "ref" and "out" are equivalent to a C++
reference:

	void function (int& value) {/* ... */}

At the compiler/runtime level, a reference is *really* a pointer, same
as above, but with the language guarantee that the pointer can never be
the null pointer (outside of reinterpret_cast).

C# ref and out is similar.  At the IL level, a manage pointer is
actually being passed, which could be null.  The language requires that
null never be passed, just like a C++ reference, and adds additional
semantic requirements ("ref" objects must be initialized before the
call, "out" objects must be initialized before function return).

> 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.

>  'null' is not an uninitialized value, it
> is explicit initialization to a null reference. If 'null' cannot be passed
> for a 'ref object' parameter, then '0' cannot be passed for a 'ref int'
> parameter :-)

And, actually, 0 cannot be passed for a `ref int' parameter:

	static void Foo (ref int n) {}
	static void Main () {
		Foo (0);
	}

Under mcs, I get:

	error CS1503: Argument 0: Cannot convert from 'int' to 'ref int&'

The same should be true for `ref object' and `null'.

See above: `ref' and `out' mean `pointer' at the IL level, and the
`pointer' must be non-null and refer to a modifiable object.

> Remember that the reference that 'ref' refers to is a
> reference to the variable in the calling context, and not to the object to
> which that variable refers. Whew, too many 'ref's in that sentence :-)

Which is why you introduce new terminology, to clear up the sentence. 
Hopefully I've cleared things up, though comparing things to C++ might
not actually clear things up. :-)

> 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.

Remember, CIL embodies the union of all (well, many) language features. 
Not all languages support all features, though, so we have the CTS which
defines a common subset of CIL which all languages should support.  For
example, CIL permits module-level functions (functions outside of a
class), which is useful for C++, but C# couldn't consume them.

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

Indeed.  For C#.

<snip/>

 - Jon





More information about the Mono-devel-list mailing list