Search code examples
c#visual-studiocompiler-construction

evaluate expression at compile time


I know this has been asked a lot, but only for C/C++ and Java. The question is related to the performance benefits of using constant expressions:

When I call a static function with only constants as arguments, is there a way to tell the compiler that it should evaluate the call already at compile time and replace the call by the result?

Example:

const double pi = Math.PI; //works as Math.PI is a constant  
const double spi = Math.Sin(Math.PI); //compiler error, because expression must be constant  

Are there no directives (better: Attributes) to tell the compiler explicitely that a static method like Math.Sin() is not modifying nor reading any data internally, so that it was technically possible to evaluate the call at compile time?

Oh, and please don't answer like "just do const double spi = 0" :), because my example is just a simplified version of the problem I have: Improving code maintainability while keeping maximum performance.

Thanks for any help - it is really appreciated!


Solution

  • For numerical constants I see two options:

    Option one: use static readonly (calculated once at startup):

    class MyCalc
    {
        private static readonly double spi = Math.Sin(Math.PI);
        private static readonly double pi = Math.PI;
    
        public void Execute()
        {
            // .. whatever
        }
    }
    

    Option two: perform calculations with your pocket calculator and hardcode those constants:

    class MyCalc
    {
        // Math.Sin(Math.Pi)
        private const double spi = 0;
        // Math.Pi
        private const double pi = 3.141592653589793;
    
        public void Execute()
        {
            // .. whatever
        }
    }
    

    I'm not sure, if the compiler can completely optimize away option one in a calculation but it should be the most readable and maintainable way.

    If you are looking for doing as much at compile-time as possible, things get harder. Under C++ you have templates. I find them cumbersome to write but people get amazing things done with it. It seems it got easier with compile time functions but I haven't tried them yet. D have CTFE which is really powerful. But D is a niche and I would avoid to write any serious code in it. I am not aware of other languages with a considerable explicit precompilation evaluation but I'm sure there are some.

    Compilers are quite smart these days. Chances are good that a compiler might see an opportunity to inline an optimize a function call without an hint. With DotNet 4.5, we've got the AggressiveInlining-attribute so we might to be able to force the compiler into the right direction. C/C++ have something similar and there had been problems. General advice from my side would be to avoid inline until you exactly know what you are doing.

    If you really wan't to go this way from C#, the best option in my eyes would be to write your functionality in C++ using the mentioned features, write an easy to use C-interface and call it by PInvoke. But do yourself a favor and measure before if it is really worth it. Never forget the two rules of optimization:

    1. Don't
    2. Don't yet (experts only)