I think C# is forcing us to write more (redundant) code

B

Bob Powell [MVP]

Creation and assignment of variables is essentially the same for VB and C#.
Value types are assigned their normal default values. For example you don't
have to explicitly write:

int x = new int(12);

and if you just use "int x;" then x contains zero.

Reference types are assigned null by the framework too.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
Actualy they are, the IL directive .locals init, emitted by C# , VB.NET and
ME C++, is a hint for the JIT to initialize the locals (stack as well as
register allocated) to 0 (zero).

That may be true of the implementation, but not of the specification. I
should have made that clearer - it's actually important when it comes
to calling methods with "out" parameters written in other languages,
but within C# the value is effectively unspecified. This is perhaps
unfortunate...
 
W

Willy Denoyette [MVP]

Neo The One said:
I have not read the spec yet...

But if what you said is true, then C# compiler is generating REDUNDANT
code
or at least it should not emit the init flag. Because init flag initialize
local vars, that takes CPU time.

This flag is required by all languages that generate verifiable code, please
read the CLI specs.

By C# rule, before reading any local var, I
have explicitly assign a value to it; if I assign a non-default value, the
previous initialization is redundant and waste of CPU cycles;
Again, this is also true for VB.NET and all other languages to generate
verifiable code.

if I assign a
default value, the previous initialization is also redundant and a waste
of
CPU time. So the conclusion is the code generated by C# compiler is
redundant.
Same here, see above....
I do think that the rule that local vars must be explicitly assigned
before
reading their values is wise and it ensures secure and correct code. I
never
doubt the design of the language spec. But now the problem is that C#
compiler is generating code that is not optmized, which we C/C++
programmers
always care about and object to.

These 'redundant' init, take two CPU cycles on modern CPU's, you don't care
about these don't you? Do you know how many cycles are needed to push/pop
registers on the stack, even when they aren't used in the called method?
Do you know how many cycles it takes to initialize an exception frame when
your method contains a protected block, like the following?

F()
{
string s = nul;
try {
...
}
....

is this a reason for C/C++ not to use exceptions in C++? I guess not.
Agreed, the JIT could optimize away the redundant init's, but then the JIT
has to burn some extra (redundant?) cycles for it.
Anyway, if you really think this is an issue, I would suggest you stick with
C (he! stay away from C++ too) or start to code in assembly if you realy
want to save the last cycle, but this is not what modern languages should
(too much) care about.

Willy.
 
W

Willy Denoyette [MVP]

Jon Skeet said:
I think it's arguable.
See below.
No, it has to point to an actual reference.

No its not, passing a pointer to a 'null' reference is valid, how would you
explain following is valid, or do you call null an actual reference?.

{
string s;
// or this...
// string s = null;
F(out s);
Console.WriteLine(s);

}
static void F(out string s)
{
s = "test";
}
But that's the point - it's only compiler enforced in C#, and you might
be calling into non-C# code. Even using C#, if you use RealProxy to
implement an interface, you can get that initial value as an object
reference. Imagine if it were a reference to some sensitive piece of
memory elsewhere - very bad news from a security point of view.

But who is talking about a pointer to memory elsewhere, we are talking about
locals here and locals are stack allocated, the variable declaration
reserves the location on the stack to hold the variable (whatever its type)
while the out keyword tells the compiler to take the address of the value as
argument, it MUST point to a valid memory location (this is the JIT's task),
but the 'value' it points to doesn't matter, is not verified and so it can
be bit combination.
That means that in this snip:

string s;
string ss = "Just a string";
// this..
string s = null;
// and these
// string s = "Whatever";
// string s = ss;
F(out s);
...
static void F(out string s)
{
s = ...
}

are all valid, all that's required is that the callee assigns the 'value'
pointed to by the argument (a pointer) before leaving the method scope
(again this is compiler enforced).

So, this is not valid...
static void F(out string s)
{ // do whatever, but don't assign to s... }

It may be up to the callee to know the semantics, but unless the CLI
spec (which I haven't checked) says that those semantics are actually
enforced, you could still have managed code with a nasty security
problem if the "uninitialised" value could be examined.

Hmmm, I didn't say the CLI imposes something here, I was talking about
PInvoke and as the callee is unmanaged code we aren't going to discuss
security and other things that might go wrong, if you call into unmanaged
code, all gates are open. What I meant was when passing an argument as
'out', it's up to the interop layer to correctly marshal the pointer or the
data it points to, depending on the argument type and it's attributes. If
there is something wrong with one of these, bad things can happen and the
CLI has nothing to with this.
Sorry, I'm completely lost here I'm starting to think we are talking about
different things here, the OP and I are saying that locals are initialized
to zero, the while the C# specs. explicitely state that "locals are NOT
initialized and they don't contain default values", note that the specs
don't say "you should not assume that locals are compiler initialized'.
I don't have a problem with this explicit initialization in the current
implementation[1], but the OP's point is the redundant initialization
imposed by the C# compiler (also not an issue for me) , while it's not
required by VB.NET nor by C++/CLI.

// this is redundant in the current implementation, but it's C# compiler
enforced, which is not true for the other compilers.
int aLocal = 0;

[1] all MSFT compilers emit .locals init and as such sets the locals to 0
(not explicitly required as per C# specs).


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top