Mathematical operations on arbitrary objects in C #

I use an interpreter for a toy language in C #, and to do the math in that language I would like to implement a function like this:

public static object Add( object a, object b ) { // return the sum of a and b // each might be int, double, or one of many other numeric types } 

I can imagine a very stupid and poor implementation of this function with tons of branches based on types a and b (using the is operator) and a bunch of castings, but my instinct is that there is a better way.

Do you think a good implementation of this feature will be?

+4
source share
5 answers

If:

  • you just need a simple solution in the program
  • your little language has the same arithmetic rules as C #
  • you can use c # 4
  • you don't really like performance

then you can just do this:

 public static object Add(dynamic left, dynamic right) { return left + right; } 

Done. What happens when this method is called, the code starts the C # compiler again and asks the compiler: "What would you do if you had to add these two things, but did you know their types of execution at compile time?" (The Dynamic Language Runtime then caches the result so that the next time someone tries to add two ints, the compiler does not start again, they just reuse the lambda that the compiler returned to DLR.)

If you want to implement your own rules for adding, welcome to my world. There is no magic road that avoids a lot of checks and type switches. There are literally hundreds of possible cases for adding two arbitrary types, and you should check them out.

How we deal with this complexity in C #, we define addition operations on a smaller subset of types: int, uint, long, ulong, decimal, double, float, all enums, all delegates, string, and all valid versions of these value types. (Then the enumerations are considered as their basic types, which simplifies further actions.)

So, for example, when you add an abbreviation to an abbreviation, we simplify the problem by saying that ushort and short are both special cases of int, and then solve the problem of adding two ints. This greatly reduces the amount of code we need to write. But believe me, the algorithm for converting binary operators to C # is many thousands of lines of code. This is not an easy task.

If your toy language is designed for a dynamic language with its own rules, you might consider introducing IDynamicMetaObjectProvider and using DLR mechanisms to implement arithmetic and other operations, such as calling a function.

+19
source

Convert your values ​​to the widest type, such as decimal. All types, such as int, double, short, etc., implement the IConvertible interface ( http://msdn.microsoft.com/en-us/library/system.iconvertible_members.aspx ). It provides a ToDecimal method that can be used to convert a value to a decimal type. The Convert class is also very useful.

 decimal aop = Convert.ToDecimal(a); decimal bop = Convert.ToDecimal(b); decimal sum = aop + bop; return Convert.ChangeType(sum, typeof(a)); // Changing type from decimal to type of the first operand. 
+6
source

One thing you can do is write your own base of objects for the toy language. It can be either a real class or an interface. This way you can make sure that all your classes have some kind of functionality for all operations (even if it is only to throw a NotSupported exception at runtime). You can do this using an interface or abstract functions for really common things (like ToString or Equals) or using message passing or some other method for unusual operations.

(ps I am cross-hosted with STO, but I like the idea of ​​STO for numeric types.)

+1
source

The easiest way to do this right away is to simply check the types, as you said.

But since this is for the implementation of the toy language (useful for you!), I would suggest using a better abstraction than object to convey values ​​in your interpreter. perhaps create a base class LanguageNameObject , and then you can add all the helper methods that you want to help implement this method. Basically, the object class is a bad abstraction for you to work with ... so build the best!

+1
source

I'm interested, I would use the typeof () operator for incoming objects and test them against types that you allow Add operations to do. I also assume that you will throw an exception if the oddball types are trying to add together?

Ideally, however, if you only let int, float, double, etc. be added, I would just create an overloaded version of the Add method to handle these various cases.

0
source

All Articles