Skip to content

Deprecate QuantityType to better support custom quantities #864

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

Merged
merged 15 commits into from
Dec 17, 2020
Merged

Deprecate QuantityType to better support custom quantities #864

merged 15 commits into from
Dec 17, 2020

Conversation

generateui
Copy link
Contributor

See #858. Turns out, QuantityInfo is already sufficient to represent a type of quantity. Hence, the solution is simple: remove QuantityType.

Tests pass, but I have not done a thorough check to actually merge the PR. Let's discuss first if this solution is desirable. To me, it solves the problem - QuantityType is gone, extensibility on QuantityType is now irrelevant.

Furthermore, users of all quantities can now use Quantity.ByName to enumerate all quantities.

Please let me know if this is the direction this library want to go into. If so, I'll publish follow up changes to ready up for a merge.

Copy link
Owner

@angularsen angularsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you made an excellent observation that we can reuse QuantityInfo instead of QuantityType for enumerating quantities, looking up one statically via Length.Info or dynamically via Quantity.Infos.

As in my comments, I propose we revert to keep old functionality and keep it backwards compatible, but mark it obsolete. Unit tests should test both old and new, until removed.

Then update #180 with what to remove and cleanup when we bump the major version.
There is a bunch of other stuff waiting there already.

What I didn't immediately see, is how do we achieve more extensibility than before?

Wiki describes how to extend with custom units, for converting or parsing, but it doesn't describe how to add custom quantities. One specific thing I believe is missing is how to add HowMuch to Quantity.Infos, which is currently an array. I can't immediately think of other scenarios where extensibility is lacking, but I'm sure there is something.

I'm totally fine with attacking that point later, just wanted to bring it up to hear if you had any thoughts of it.

@generateui
Copy link
Contributor Author

generateui commented Dec 5, 2020

Right, I forgot UnitsNet supports graceful removal of features. Obsoleting first makes total sense. Agreed that only when actual removal is done, tests should be removed.

Would you please update #180, when the time is there?

What I didn't immediately see, is how do we achieve more extensibility than before?

We don't. We just remove a blocker on extensibility by changing the fact that the library relies on QuantityType. The PR effectively moves QuantityType to a role where it is not required to use any more, which is needed for extended quantities. Extended quantities can't provide a correct QuantityType value, and as such using api's where QuantityType is used will fail. That is what this PR fixes.

I have opened #865 to discuss extensibility features in a tracking issue.

I will update the PR to support obsoletion and initial addition of the QuantityInfo apis.

@generateui
Copy link
Contributor Author

I will update the PR to support obsoletion and initial addition of the QuantityInfo apis.

Done. Could you re-review? Thanks!

Copy link
Owner

@angularsen angularsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good progress, some findings below.

@angularsen
Copy link
Owner

Seems like tests fail on NullReferenceException in the build:

https://ci.appveyor.com/project/angularsen/unitsnet/builds/36677657

Failed UnitsNet.Tests.CustomCode.ThermalConductivityTests.ToString_ReturnsValueAndUnitAbbreviationInCurrentCulture [1 ms]
  Error Message:
   System.TypeInitializationException : The type initializer for 'UnitsNet.ThermalConductivity' threw an exception.
---- System.TypeInitializationException : The type initializer for 'UnitsNet.Quantity' threw an exception.
-------- System.TypeInitializationException : The type initializer for 'UnitsNet.Acceleration' threw an exception.
------------ System.NullReferenceException : Object reference not set to an instance of an object.
  Stack Trace:
     at UnitsNet.ThermalConductivity..ctor(Double value, ThermalConductivityUnit unit) in C:\projects\unitsnet\UnitsNet\GeneratedCode\Quantities\ThermalConductivity.g.cs:line 71
   at UnitsNet.Tests.ThermalConductivityTestsBase.ToString_ReturnsValueAndUnitAbbreviationInCurrentCulture() in C:\projects\unitsnet\UnitsNet.Tests\GeneratedCode\TestsBase\ThermalConductivityTestsBase.g.cs:line 360
----- Inner Stack Trace -----
   at UnitsNet.QuantityInfo..ctor(String name, UnitInfo[] unitInfos, Enum baseUnit, IQuantity zero, BaseDimensions baseDimensions) in C:\projects\unitsnet\UnitsNet\QuantityInfo.cs:line 99
   at UnitsNet.QuantityInfo`1..ctor(String name, UnitInfo`1[] unitInfos, TUnit baseUnit, IQuantity`1 zero, BaseDimensions baseDimensions) in C:\projects\unitsnet\UnitsNet\QuantityInfo.cs:line 238
   at UnitsNet.ThermalConductivity..cctor() in C:\projects\unitsnet\UnitsNet\GeneratedCode\Quantities\ThermalConductivity.g.cs:line 56
----- Inner Stack Trace -----
   at UnitsNet.Acceleration.FromMetersPerSecondSquared(QuantityValue meterspersecondsquared) in C:\projects\unitsnet\UnitsNet\GeneratedCode\Quantities\Acceleration.g.cs:line 358
   at UnitsNet.Tests.DecimalOverloadTests.CreatingQuantityWithDoubleBackingFieldFromDecimalReturnsCorrectValue() in C:\projects\unitsnet\UnitsNet.Tests\DecimalOverloadTests.cs:line 13
----- Inner Stack Trace -----
   at UnitsNet.QuantityInfo..ctor(String name, UnitInfo[] unitInfos, Enum baseUnit, IQuantity zero, BaseDimensions baseDimensions) in C:\projects\unitsnet\UnitsNet\QuantityInfo.cs:line 99
   at UnitsNet.QuantityInfo`1..ctor(String name, UnitInfo`1[] unitInfos, TUnit baseUnit, IQuantity`1 zero, BaseDimensions baseDimensions) in C:\projects\unitsnet\UnitsNet\QuantityInfo.cs:line 238
   at UnitsNet.Acceleration..cctor() in C:\projects\unitsnet\UnitsNet\GeneratedCode\Quantities\Acceleration.g.cs:line 53
  Failed UnitsNet.Tests.CustomCode.ThermalConductivityTests.ConversionRoundTrip [1 ms]
  Error Message:

@generateui
Copy link
Contributor Author

I have fixed some warnings and fought a little fight with Visual Studio, resulting in #pragma littering. That seems to be fixed now (I still wonder why previous week the build succeeded and now a reboot and restart reports all these warnings as errors. The ways of VS move in mysterious ways).

I can't reproduce the error. Tracing it back points to

            if (Quantity.QuantityTypeByName.TryGetValue(name, out var quantityType))
                QuantityType = quantityType;
            else
                QuantityType = QuantityType.Undefined;

in the ctor of public QuantityInfo([NotNull] string name, [NotNull] UnitInfo[] unitInfos, [NotNull] Enum baseUnit, [NotNull] IQuantity zero, [NotNull] BaseDimensions baseDimensions). Yet, this dictionary is initialized and all tests pass locally. Can you take a look?

Pass QuantityType as argument with default value, instead of looking up in Quantity.
@angularsen angularsen changed the title remove QuantityType Deprecate QuantityType to support custom quantities by name Dec 12, 2020
@angularsen angularsen changed the title Deprecate QuantityType to support custom quantities by name Deprecate QuantityType to better support custom quantities Dec 12, 2020
@angularsen
Copy link
Owner

I pushed some fixes on a cyclic static ctor call, and fixed some test cases.
It builds and all tests pass locally with build.bat now.

@codecov
Copy link

codecov bot commented Dec 12, 2020

Codecov Report

Merging #864 (eb2f1e1) into master (4993a2a) will decrease coverage by 0.36%.
The diff coverage is 80.39%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #864      +/-   ##
==========================================
- Coverage   83.09%   82.73%   -0.37%     
==========================================
  Files         287      287              
  Lines       42987    43308     +321     
==========================================
+ Hits        35720    35829     +109     
- Misses       7267     7479     +212     
Impacted Files Coverage Δ
UnitsNet/UnitConverter.cs 82.35% <ø> (ø)
UnitsNet/GeneratedCode/Quantity.g.cs 52.00% <1.81%> (-29.41%) ⬇️
UnitsNet/CustomCode/Quantity.cs 81.08% <100.00%> (-3.13%) ⬇️
...nitsNet/GeneratedCode/Quantities/Acceleration.g.cs 82.56% <100.00%> (+0.09%) ⬆️
...et/GeneratedCode/Quantities/AmountOfSubstance.g.cs 82.88% <100.00%> (+0.09%) ⬆️
...tsNet/GeneratedCode/Quantities/AmplitudeRatio.g.cs 77.77% <100.00%> (+0.15%) ⬆️
UnitsNet/GeneratedCode/Quantities/Angle.g.cs 82.01% <100.00%> (+0.09%) ⬆️
...tsNet/GeneratedCode/Quantities/ApparentEnergy.g.cs 77.24% <100.00%> (+0.15%) ⬆️
...itsNet/GeneratedCode/Quantities/ApparentPower.g.cs 77.77% <100.00%> (+0.15%) ⬆️
UnitsNet/GeneratedCode/Quantities/Area.g.cs 84.46% <100.00%> (+0.08%) ⬆️
... and 100 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4993a2a...eb2f1e1. Read the comment docs.

@angularsen
Copy link
Owner

AppVeyor is happy, I'll try to re-review this soon.

@generateui
Copy link
Contributor Author

How come the cyclic ctor call did not explode on my machine? I ran all tests.

@angularsen
Copy link
Owner

angularsen commented Dec 13, 2020

Try running build.bat. That excludes any quirks by Visual Studio and Rider, using dotnet CLI to run tests.

One thing is that the order of tests. If any test in the same app domain (test project) called Quantity type, then Quantity static ctor would successfully init.
If a test called Temperature.Info first, then it would cause problems.

My best guess is that you were "lucky" to not get that particular test execution order.

@generateui
Copy link
Contributor Author

Gotcha, thanks. Is there anything you want me to do to move forward on this PR?

@angularsen
Copy link
Owner

No, I just need to read through the whole PR again. Maybe tomorrow.

Replace MSBuildTreatWarningsAsErrors with TreatWarningsAsErrors
Demote nullability errors to warnings in CodeGen until fixed.
@angularsen
Copy link
Owner

@generateui I think this is ready to merge! Just waiting for AppVeyor to do its thing. It has been awfully slow lately.

@angularsen
Copy link
Owner

I was able to sort out the pragma stuff, see #872 .

@angularsen
Copy link
Owner

Quantity.g.cs had 30% lower test coverage, but we can sort that out later. I'd rather merge this beast now :D

If I read it right, the method is not covered by tests:
FromQuantityInfo

https://codecov.io/gh/angularsen/UnitsNet/pull/864/diff?src=pr&el=tree#diff-VW5pdHNOZXQvR2VuZXJhdGVkQ29kZS9RdWFudGl0eS5nLmNz

@angularsen angularsen merged commit c46d064 into angularsen:master Dec 17, 2020
@angularsen
Copy link
Owner

Nuget is on the way out, thank you for the contribution!

Release UnitsNet/4.79.0 · angularsen/UnitsNet

@generateui
Copy link
Contributor Author

This is awesome! Thanks for your close support.

@generateui generateui deleted the no-quantity-type branch December 19, 2020 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants