Scope confusion -- compilation issue -- please help me understand

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

When I compile the following code fragment, the compiler errors saying the variable connection is not initialized. As I understand C#, I thought it would be initialized. Please help me and explain what I am missing

Bil

static void Main(string[] args

SqlConnection connection
try // to open the connection to the database

connection=new SqlConnection((string)( System.Configuration.ConfigurationSettings.AppSettings["SQLConnection"]))
connection.Open()

catch (Exception e

ProcessInitialException(e)
Environment.Exit(0)

if (args.Length!=2

ProcessArguementError(args)
Environment.Exit(0)

string eventType=args[0]
string userEvent=args[1]
SqlCommand command=new SqlCommand("RetrieveNotificationUsers",connection)
 
The problem is that the compiler doesn't know that Environment.Exit never
returns. So if the constructor for SqlConnection threw an exception (leaving
connection uninitialised), the compiler would consider the use of connection
in the last line a potential problem. You and I know better of course.

As far as I know the best way to avoid this is to stick a 'throw new
Exception()' after the first Environment.Exit, but if somebody knows of an
attribute or similar that could be employed in this sort of situation I'd be
interested.

Stu


Bill said:
When I compile the following code fragment, the compiler errors saying the
variable connection is not initialized. As I understand C#, I thought it
would be initialized. Please help me and explain what I am missing.
Bill

static void Main(string[] args)
{
SqlConnection connection;
try // to open the connection to the database.
{
connection=new SqlConnection((string)( System.Configuration.ConfigurationSettings.AppSettings["SQLConnection"]));
connection.Open();
}
catch (Exception e)
{
ProcessInitialException(e);
Environment.Exit(0);
}
if (args.Length!=2 )
{
ProcessArguementError(args);
Environment.Exit(0);
}
string eventType=args[0];
string userEvent=args[1];
SqlCommand command=new SqlCommand("RetrieveNotificationUsers",connection);
 
Bill said:
When I compile the following code fragment, the compiler errors
saying the variable connection is not initialized. As I understand
C#, I thought it would be initialized. Please help me and explain
what I am missing.

The problem is that the compiler doesn't know that Environment.Exit(0)
is going to quit the runtime, so it thinks that it's possible for you
to throw and catch an exception, and then move on to the later bit of
code - which would involve reading the connection variable which
wouldn't have been initialised.

You could stick a return statement after Environment.Exit(0); which
wouldn't do any harm but would clear the error - or set the connection
to null to start with.
 
Belay my last.

Really, unless there is some reason that getting the SQLConnection key
from the appsettings would fail, I would take that line out of the
try//catch altogether. So you would just have

SqlConnection connection = new
SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["SqlConnection"]);
and then try to open the connection.

You shouldn't need to cast that to (string) since
AppSettings["blahblah"] should be returning a string anyway.

In order for it to compile, you need connection to be initialized to
*something* to reference it later, and since the code in try{} may not
run, the compiler does not recognize that it would work, and throws the
error.

Keep your trys as lean as possible, as try{}catch{} runs pretty slow.
 
----- Scott C. Reynolds wrote: ----
Keep your trys as lean as possible, as try{}catch{} runs pretty slow

no, there's only performance penalty if an exception was actually thrown. I've never read any standard saying to keep your try block lean.
 
You know, you are right. I have never given it that much thought. You
should avoid exception handling just for the sake of exception handling
(such as catching something that could have easily been handled with an
if()), but there is no reason not to put whatever you want in the try
block. It has just always been my practice to try{thebareminimum();},
but it is by no means required.

So, it is back to initialize connection to null before the try block, or
pull the creating the instance out of the try anyway unless you feel
like it might fail, because one way or the other the compiler doesn't
know you are exiting the application and will nag you if you try to use
a potentially uninitialzed object.
 
Daniel Jin said:
----- Scott C. Reynolds wrote: -----
slow.

no, there's only performance penalty if an exception was actually
thrown. I've never read any standard saying to keep your try block lean.

This is not true.

Setting up the try-block do indeed cost several 100'000 cycles. For typical
applications this is neglectable. For high-performing tight heavy loops -
exception handling (try-blocks inside the loop) do takes it toll and really
hurts performance.

But in this context, using a sql connection, I would never even consider
getting rid of the try-block. Not for readablility and certainly not for
performance reasons.

Best Regards
- Michael S
 
Hi, Michael

How did you get the figures for try/catch? Any pointers to benchmarks or
test samples?
 
Michael S said:
This is not true.

Setting up the try-block do indeed cost several 100'000 cycles.

While I agree it's not absolutely free, I don't think it takes *that*
much time. For instance:

using System;

public class Test
{
static int x;
static int y=0;

const int Iterations = 100000000;

static void Main()
{
y=1;
DateTime start=DateTime.Now;
for (int i=0; i < Iterations; i++)
{
IncX();
}
DateTime end=DateTime.Now;

Console.WriteLine ("Time for {0} iterations: {1}",
Iterations, end-start);
}

static void IncX()
{
try
{
if (y==0)
{
throw new Exception ("Whoops");
}
x++;
}
catch (Exception e)
{
throw new ApplicationException("Yikes "+e.Message);
}
}
}

On my P4/3GHz laptop, the results are that it takes about a second for
the 100,000,000 iterations. If each iteration were taking even one
hundred thousand cycles, that would suggest that my laptop were capable
of executing 10^13 cycles per second. I don't believe that's the case.

Note that if I replace IncX with:

[MethodImpl(MethodImplOptions.NoInlining)]
static void IncX()
{
x++;
}

the test takes between 0.4 and 0.8 seconds. Say it takes about half the
time of the version which includes try/catch. That suggests that

method invocation + try/catch + increment takes twice as long as
method invocation + increment

In other words, the cost of setting up a try/catch is the same as a
method invocation and an increment. Do you really think that *that*
takes several hundred thousand cycles?
 
Thanks Jon for dropping some stats and sample.

On my 1GHz your test shows that try/catch in static method body increases
runtime on average by 0.75 sec for 100M iterations. Approx. 30% of total
execution time (2.3). Considering that clean x++ in for loop gives me around
0.65, I would say that overhead is not significantly more than general cost
of for body, which is 12 IL ops like stloc/ldloc, ldsfld/stsfld, blt, ldc
and couple of add.

I would conclude, that general cost of setting up try/catch block is
negligible for nearly all .Net applications. It is worth to consider related
overhead only in computation intensive cases and even then it is
questionable if result is worth the effort.

Rgds
Alex


Jon Skeet said:
Michael S said:
This is not true.

Setting up the try-block do indeed cost several 100'000 cycles.

While I agree it's not absolutely free, I don't think it takes *that*
much time. For instance:

using System;

public class Test
{
static int x;
static int y=0;

const int Iterations = 100000000;

static void Main()
{
y=1;
DateTime start=DateTime.Now;
for (int i=0; i < Iterations; i++)
{
IncX();
}
DateTime end=DateTime.Now;

Console.WriteLine ("Time for {0} iterations: {1}",
Iterations, end-start);
}

static void IncX()
{
try
{
if (y==0)
{
throw new Exception ("Whoops");
}
x++;
}
catch (Exception e)
{
throw new ApplicationException("Yikes "+e.Message);
}
}
}

On my P4/3GHz laptop, the results are that it takes about a second for
the 100,000,000 iterations. If each iteration were taking even one
hundred thousand cycles, that would suggest that my laptop were capable
of executing 10^13 cycles per second. I don't believe that's the case.

Note that if I replace IncX with:

[MethodImpl(MethodImplOptions.NoInlining)]
static void IncX()
{
x++;
}

the test takes between 0.4 and 0.8 seconds. Say it takes about half the
time of the version which includes try/catch. That suggests that

method invocation + try/catch + increment takes twice as long as
method invocation + increment

In other words, the cost of setting up a try/catch is the same as a
method invocation and an increment. Do you really think that *that*
takes several hundred thousand cycles?
 
Hi Jon.

About my *that* long time it's something I remembered from a discussion on
Microsoft C++ and Borland Delphi compilers. I have no links, sorry.

Regarding your test; Was it compiled in debug or release mode? Also, for
such a small scale test, using DateTime.Now to time performance is way to
crude.

The point is still made clear: Setting up a try-block take *some* time. For
tight loops there is a noticable penalty. However, getting rid of try blocks
for performance considerations is just plain wrong. Agreed?

Best Regards
- Michael S

ps.
On a more funny side: A friend of mine applied for work at a game-shop. As
he being brainwashed by managed code (mainly in Java), at the job interview,
he started talking about the importance of exception handling, assertions,
interfaces and factories for making robust quality code. Their response
was: - We do computer games. Most our code is in asm!

... He didn't get the job... =)


Jon Skeet said:
Michael S said:
This is not true.

Setting up the try-block do indeed cost several 100'000 cycles.

While I agree it's not absolutely free, I don't think it takes *that*
much time. For instance:

using System;

public class Test
{
static int x;
static int y=0;

const int Iterations = 100000000;

static void Main()
{
y=1;
DateTime start=DateTime.Now;
for (int i=0; i < Iterations; i++)
{
IncX();
}
DateTime end=DateTime.Now;

Console.WriteLine ("Time for {0} iterations: {1}",
Iterations, end-start);
}

static void IncX()
{
try
{
if (y==0)
{
throw new Exception ("Whoops");
}
x++;
}
catch (Exception e)
{
throw new ApplicationException("Yikes "+e.Message);
}
}
}

On my P4/3GHz laptop, the results are that it takes about a second for
the 100,000,000 iterations. If each iteration were taking even one
hundred thousand cycles, that would suggest that my laptop were capable
of executing 10^13 cycles per second. I don't believe that's the case.

Note that if I replace IncX with:

[MethodImpl(MethodImplOptions.NoInlining)]
static void IncX()
{
x++;
}

the test takes between 0.4 and 0.8 seconds. Say it takes about half the
time of the version which includes try/catch. That suggests that

method invocation + try/catch + increment takes twice as long as
method invocation + increment

In other words, the cost of setting up a try/catch is the same as a
method invocation and an increment. Do you really think that *that*
takes several hundred thousand cycles?
 
Michael S said:
About my *that* long time it's something I remembered from a discussion on
Microsoft C++ and Borland Delphi compilers. I have no links, sorry.

Regarding your test; Was it compiled in debug or release mode?
Release.

Also, for
such a small scale test, using DateTime.Now to time performance is way to
crude.

It's not so bad on a second or so. Much less than that and it's too
crude, I'll admit. It doesn't matter here though - these were only
rough timings, and it was obvious that it was taking "about a second".
If I'd been interested in very accurate timings, I'd have upped the
number of iterations.
The point is still made clear: Setting up a try-block take *some* time. For
tight loops there is a noticable penalty. However, getting rid of try blocks
for performance considerations is just plain wrong. Agreed?

Agreed. If it were really taking hundreds of thousands of cycles,
however, it *would* be a valid thing to try to optimise in many
situations. As it is, only a very tight loop would benefit
significantly from removing it.
ps.
On a more funny side: A friend of mine applied for work at a game-shop. As
he being brainwashed by managed code (mainly in Java), at the job interview,
he started talking about the importance of exception handling, assertions,
interfaces and factories for making robust quality code. Their response
was: - We do computer games. Most our code is in asm!

.. He didn't get the job... =)

Interesting, as most games are (I believe) written in C or C++ these
days...
 
Back
Top