user24296292
user24296292

Reputation:

How can I write more efficient code? Or, why does a decompiler produce code that appears less efficient than what I wrote?

When writing my library, I used a series of ternary expressions:

public INumber Level1()
{
  INumber number = Level2();
  Next();
  return
    txt == "-" ?
    new Subtraction(number, Level1()) :
    txt == "+" ?
    new Addition(number, Level1()) :
    txt == "/" ?
    new Division(number, Level1()) :
    txt == "*" ?
    new Multiplication(number, Level1()) :
    number;
}

However, when I decompile the code I see that it became a terrible implementation (in my opinion):

public INumber Level1()
{
  INumber number = Level2();
  Next();
  if (!(txt == "-"))
  {
    if (!(txt == "+"))
    {
      if (!(txt == "/"))
      {
        if (!(txt == "*"))
        {
          return number;
        }
        else
        {
          INumber number2 = new Multiplication(number, Level1());
          result = number2;
        }
      }
      else
      {
        INumber number2 = new Division(number, Level1());
        result = number2;
      }
    }
    else
    {
      INumber number2 = new Addition(number, Level1());
      result = number2;
    }
  }
  else
  {
    INumber number2 = new Subtraction(number, Level1());
    result = number2;
  }
  return result;
}

When I test my code, tests pass.

I don't understand why the decompiler produces output that is different from what I originally wrote, and, I am not sure I understand how to write efficient code.

Is there a more efficient way for me to write this code?

Upvotes: -3

Views: 150

Answers (2)

Guru Stron
Guru Stron

Reputation: 142008

I don't understand why this is happening

Compiler will translate your code into the IL (Intermediate Language) and from what I can see this is a quirk of the decompiler. For example the following:

public class C {
    public int M(string txt) => txt == "1"
        ? 1
        : txt == "2"
            ? 2
            : 3;
}

Is translated to something like:

IL_0000: ldarg.1
IL_0001: ldstr "1"
IL_0006: call bool [System.Runtime]System.String::op_Equality(string, string)
IL_000b: brtrue.s IL_001e

IL_000d: ldarg.1
IL_000e: ldstr "2"
IL_0013: call bool [System.Runtime]System.String::op_Equality(string, string)
IL_0018: brtrue.s IL_001c

IL_001a: ldc.i4.3
IL_001b: ret

IL_001c: ldc.i4.2
IL_001d: ret

IL_001e: ldc.i4.1
IL_001f: ret

Which based on the brtrue.s code does not reverse the condition. But multiple language constructions can lead to the same IL so decompilers need to do some guess work hence the result you see.

Now I don't understand how to write the code correctly is it even possible to fix it

It is written correctly and does not need "fixing". At least to some extent.

But I'm not doing an inversion of the bool value.

You should not bother, compiler should generate a correct code (at least usually). If you want - write a unit test verifying the behavior.

And last but not least. In this particular case switch (statement or expression) seems to be a much more appropriate construction to use (at least from readability/maintainability point of view). For example via switch expression:

return txt switch 
{
   "-" => Substruction(...),
   "+" => Addition(...),
   // ...
   _ => number
}

Upvotes: 0

wilson0x4d
wilson0x4d

Reputation: 8749

Presumably, you are looking at the output of a decompiler.

Decompilers generate code based on the CIL/MSIL (aka bytecode) of the assembly. This does not have a 1:1 relationship with high level languages like C#.

ECMA-335 Part III contains a definition of CIL.

Studying CIL you will find there is no such thing as a "ternary operator" instruction. Thus, a decompiler would generate code that looked like simple comparisons (if statements).

Fundamentally, a series of if statements and a ternary expression are identical at run-time, there is no distinction between these two in Intermediate Language nor Machine Language.

Some decompilers may use PDB/Debug information to assist in generating original code, and this may allow a decompiler to produce ternary expressions as output, but it would essentially be "cheating" as there is no way to know that the programmer used a ternary expression based on the IL alone.

You can use tools such as ildasm to check the IL of your code.

References

Upvotes: 0

Related Questions