How can I write a single class to compile multiple times with different number types?
Asked Answered
V

3

5

I'm trying to write classes which handle different number types. I know that C# (and .Net in general, I believe) has no INumber interface, so I cannot use something like the following:

    public class Adder<T> where T:INumber
    {
        public T Add(T a, T b)
        {
            return a + b;
        }
    }

That's okay, though, because I'd like to avoid the boxing/unboxing of every one of my numbers. I could, however, use conditional compilation for each type I want to support:

#if FLOAT 
    public class AdderF
    {
        public float Add(float a, float b)
#else
    public class Adder
    {
        public int Add(int a, int b)
#endif
        {
            return a + b;
        }
    }

This means I'll need to compile a different Library.dll and LibraryF.dll, however. Is there any more elegant solution to this?

Obviously, in my example, I can simply write the code twice. I would like to use this process, however, to create large complicated data structures with an integer version and floating-point version, so do not want the possibility of copy-paste errors when updating my structure. Nor do I want the speed loss from wrapping the floating-point structure in an integral-wrapper, and unnecessarily converting all inputs to the more lenient data type.

Vaientina answered 1/7, 2011 at 15:44 Comment(0)
M
3

I guess it depends on how strict you want it to be. Do you want an Add method that only takes two parameters of the exact same type (int and int, float and float) ... ? If not, and performance is not super-important, then you can just implement your solution with decimal and it will all work.

If it does have to be strict, and you want specific versions per type, you may want to look into T4 code generation. It's akin to C++'s templates (some people think C++ templates and C# generics are the same, but they're not).

Scott Hanselman wrote an interesting article about it.

Musca answered 1/7, 2011 at 15:52 Comment(1)
Like I said, I'm trying to coax more performance out of my data structures, and I don't think that using decimals everywhere when I could be using ints instead would be effective for that. T4 is definitely a cool technology I didn't know about, and will certainly be looking into it!Vaientina
D
3

Maybe this could be useful: Is there a C# generic constraint for "real number" types?.

It seems that it's not directly possible as you have said. It would be useful to have it.

Dollar answered 1/7, 2011 at 15:53 Comment(1)
Thanks! I was looking for a link like that to include with my question. I know that I can use abstract calculators like that to work with various number types, but my point here is to coax more performance out of integer structures when floating point precision isn't necessary.Vaientina
N
2

The main challenge here is that the jitter has to emit different opcodes depending on whether you're adding floats or ints, so, even though the code looks similar, it's actually quite different behind the scenes. This is doable in C++ (because templates are compiled separately for each type definition), but .NET generics work differently. Take a look at T4 templates as one possible solution (if you really need the ability to compile as float or int separately.)

Nous answered 1/7, 2011 at 15:57 Comment(2)
+1 for the explanation of C++ templates vs. .Net generics, and for the T4 suggestion.Vaientina
I actually misspoke a bit, as the compiler could, conceivably, support a 'number' constraint that allowed emitting of the Add IL OpCode (as opposed to trying to resolve an 'add' operator), with type-specific jitting handling the differences. This would still cause some limitations, as there is a separate Add.Ovf instruction for integers, so you could only support addition without integer overflow checking. The compiler would also need special-case support for understanding a 'primitive number' that is not yet a specific type, creating fun new boundary cases for Mr. Lippert.Nous

© 2022 - 2024 — McMap. All rights reserved.