The experiment of the week : for loop not all code paths return a value C#

The experiment of the week :

Some image of code on my screen
So As I mentioned in this week retro. The friend of mine decided to check if my c# didn’t get rusty and showed me following code:

[csharp]
public class WhatIsThis
{
int RertyLimit = 20;
public string DoSthRetry()
{
for(int retryAttempt = 10; retryAttempt < 0; retryAttempt++)
{
STH sth = new STH();
try
{
return sth.Do();
}
catch(Exception e)
{
if(retryAttempt == RertyLimit)
{
throw;
}
}
}
}
[/csharp]

Then he asked me

Why it is not compiling?

not all code paths return a value

You don’t see it but trying to build it will throw not all code paths return a value.

My first theory was in the catch statement. You could end up in catch not throw anything and then end method without return.

[csharp]
public string DoSth()
{

int retryAttempt = 10;
STH sth = new STH();
try
{
return sth.Do();
}
catch (Exception e)
{
if (retryAttempt == 10)
{
throw;
}
}
}
[/csharp]

The short test proves I was right. Above code is not compiling – not all code paths return a value.
But this one is:

[csharp]
public string DoSthFix()
{

int retryAttempt = 10;
STH sth = new STH();
try
{
return sth.Do();
}
catch (Exception e)
{
if (retryAttempt == 10)
{
throw;
}
return string.Empty;
}
}
[/csharp]

Important note. All code here is working but that doesn’t mean is proper code. For example, putting that return statement in catches clause would be against what the function would try to achieve.

So lets „implement our fix” – I am going to stress out again Don’t try to fix it like this in real life.

[csharp]
public string DoSthRetryFixAttempt()
{
for (int retryAttempt = 10; retryAttempt < 0; retryAttempt++)
{
STH sth = new STH();
try
{
return sth.Do();
}
catch (Exception e)
{
if (retryAttempt == RertyLimit)
{
throw;
}
return string.Empty;
}
}
}
[/csharp]

And still, it is not compiling.

So there is something happening with a loop.
Let us see a more straightforward example

[csharp]
public string LoopTest()
{

for(int i=0; i<10;i++)
{
return string.Empty;
}
}
[/csharp]

And it won’t compile either – not all code paths return a value.

Evidently, the compiler has a beef with for loop.
Same with While loop. But do-while works.

[csharp]
public string DoWhileLoopTest()
{
int i = 0;
do
{
i++;
return string.Empty;
}
while (i < 10);
}
[/csharp]

So what happened here?

The short explanation is that Run Time analyses are not checking values.
The long explanation is this based on this MSDN page.

Basically initialiser (first part of for loop)
can accept a lot of stuff including methods and other calls.

You can even setup it in a way that you won’t be ever run:

[csharp]
public void LoopNeverRun()
{
for(int i= 111 ;i<10;i++)
{
throw new ArgumentOutOfRangeException("Code should never enter this loop");
}
}
[/csharp]

So with so many options, you can’t have consistent foolproof, analysis of the loop. So creators decided not to analyse if loop will always be called.
Note this is my assumption after doing some reading and talking with few people, I wasn’t able to find the actual explanation from MS.

The compiler always assumes that loop creates at least two execution paths. One of this paths assumes that loop won’t be run even once.
Same for ifs.

Why Do while works? Cause do while always will be executed at least once!

So proper fix!

[csharp]
public string DoSthRetryFixed()
{
for (int retryAttempt = 10; retryAttempt < 0; retryAttempt++)
{
STH sth = new STH();
try
{
return sth.Do();
}
catch (Exception e)
{
if (retryAttempt == RertyLimit)
{
throw;
}
}
}
throw new ArgumentOutOfRangeException("Critical Error this code exceution path should Never Happen");
}
[/csharp]

I talked a lot about experiments, and this is a good case, I was able to improve my understanding of loops and computers. I haven’t learned anything new. But I made the connection between some pieces of information in my head.

Also, it is an excellent example that when experimenting Try to get the simplest model of the problem. It is easier to test when you have something small you will get results much faster.
Also, it is worth pointing out that single factor experiments are much easier to analyse.

If you want to read more about experiments you can check it here.

If you want to read more about coding I have series called Flowers talking about anti-patterns in test automation you can check it here.

My original plan for this blog was to be more technical. Somehow along the way it evolved into something else.  Mostly Because Flowers take so long to research.  But I want to write more about coding.

So here is my question: Do you see value post like this? Would you like to see more of them?

Dodaj komentarz