-
Notifications
You must be signed in to change notification settings - Fork 382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic Parameters For Measurement Quantities #666
Comments
Thanks for reporting @ZacharyPatten! As you described in the email, you are not interested in pursuing these improvements in UnitsNet yourself, just pointing out some source of reference we can look at when we address these two points. There are a number of related issues on this already:
Below is my reply in the email for future reference.
|
In regards to #285 I see that MathNet was mentioned as an example of generic mathematics. Do not copy MathNet's pattern. It is not scaleable. You shouldn't use abstract methods or other forms of inheritance. You should use runtime compilation. My Towel project is using runtime compilation in order to perform generic mathematics. This is a much better pattern because you don't have to write a custom implementation for every type you want to support. I wrote an old blog post about this topic if anyone is interested. However I wrote the blog post before I knew about Linq expressions!!!! Linq expressions (as I'm using in the Towel project) allow for very clean runtime compilation code. But you may still find the blog post interesting: Hope that helps. |
Thanks for your insights, I just read the blog post now and you have definitely ventured into some terrain that I haven't before. Interesting stuff about compiling at runtime. We have used c# code generation (pre-compile, not at runtime) extensively in this project and that would be one option for us as well, but it does bloat the binary size quite a bit so if we can instead reuse code for the the 3 main numeric types (float, double, decimal) that will probably save us a bunch. I believe we did discover some options for arithmetic with generics at some point - I just don't remember the details from the top of my head. @tmilnthorp had some ideas I believe. Will definitely check out your linq expressions and runtime compilation for inspiration 👍 |
Hey. I just wanted to mention that I got prototypes of "Speed" and "Acceleration" working with generics working in Towel if you want to take a look. This is significant because those are not base measurement types (they are complex/derived measurements). It required a different pattern than UnitsNet currently uses. UnitsNet only has one enum value per quantity, but the prototypes in Towel use potentially multiple enum values per quantity/measurement. Towel Speed Construction Example: Speed<double> a = new Speed<double>(1.5d, Meters / Seconds);
Speed<double> b = new Speed<double>(2.5d, Knots); // converted to length & time units under the hood Towel Acceleration Construction Example: Acceleration<double> c = new Acceleration<double>(3.5d, Meters / Seconds / Seconds); The reason I found this was necessary is because if you want to support non-rational types (example: int), then you always need to auto-convert from larger unit to smaller unit so there is minimal rounding (won't round to zero for int). I did some very primitive speed testing and my prototypes appear to still be faster (for speed and acceleration) than UnitsNet currently is regardless of the extra enum allocations. Still a lot of testing/tinkering to do, but it is working so far. :) If you don't care about supporting integer types, you probably don't need to store multiple enum values per quantity/measurement, but I wanted to support "int" as much as possible in Towel. Hope that makes sense. Just trying to help. |
Thanks a lot for chiming in @ZacharyPatten , I'm super busy with work these days and have a hard time following up, but it is much appreciated that you drop knowledge and experiences for us to learn from! I don't think we will ever support the "int" scenario you mention, but interesting to learn how you approached it. Multiple enum values is interesting, I'd have to think some more on it to comment anything meaningful on it though :-) |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Pinning this issue, at some point we need to address this. |
Would you be amenable to a major release soon with only this? |
Absolutely, if we can get generics working so we can get rid of the mix of double + decimal as well as allow the consumer to choose numeric type (float, double, decimal) then I'm game for a breaking change. Note also that #651 might be getting some traction too, which would be perfect to include in a major bump. |
I don't recall, does this mean we have to go to |
The generics will work with either classes or structs. That is a seperate topic of which is better classes or structs? I was using "struct" in my code, but I have yet to do some performance testing. |
I was going to leave it as struct |
Awesome, then I don't see any reason not to go forward with this. |
We can't merge this into |
A concept of a very generic units of measure library that may help you somehow: github. |
Interesting use of the new Math API @WhiteBlackGoose 👍 We have been contemplating how we can best utilize it for UnitsNet. I will keep this reference in mind! |
Generic Types
Right now, UnitsNet can only support "double" types. If you use generic types on the quantities you can allow for support of other types than just double.
I have working prototypes for Length, Mass, and Angle measurement types using generic paramters here:
https://github.com/ZacharyPatten/Towel
I wanted to share my patterns with UnitsNet, because they could help improve UnitsNet should they be adopted. However, there are pros/cons to my pattern, and it would be a massive overhaul of UnitsNet to incorporate generics, so it might not be feasible for the project to adopt the patterns.
Performance Optimization
The conversions in UnitsNet require a double conversion to/from a base unit. In that Towel project, I am using multiplication tables (in the form of jagged arrays) to cache the conversions between units. The index of the multiplication tables are provided by the values on the unit enums. This allows Towel to perform unit conversions with a single operation rather than double as UnitsNet is currently doing.
The text was updated successfully, but these errors were encountered: