Skip to content

Commit

Permalink
💥Remove decimal support (#1359)
Browse files Browse the repository at this point in the history
### Changes
- Remove `QuantityValue`, replaced with `double`
- Remove `TValueType` from interfaces
	- Remove `IQuantity<TUnitType, out TValueType>`
	- Remove `IValueQuantity<out TValueType>`
- Change `IQuantity<TSelf, TUnitType, out TValueType>` to
`IQuantity<TSelf, TUnitType>`
- Change `IArithmeticQuantity<TSelf, TUnitType, TValueType>` to
`IArithmeticQuantity<TSelf, TUnitType>`

### Changes to UnitsNet.Serialiation.JsonNet
- Deserializing previously serialized JSON for decimal quantities
`Information`, `BitRate` and `Power` still work, but it now reads just
`double Value` property and ignores `string ValueString` and `string
ValueType` properties. This may lose precision compared to preserving
the full `decimal` value, but `decimal` is no longer supported in v6.


### Background
In #1195 @angularsen says:

> If we change all 3 quantities to double, we have the potential to
clean up a LOT of QuantityValue complexity.

This made me wonder how deep that complexity goes so I decided to
experiment, and this is the result.

I must say some of these changes make me a bit sad. A lot of work and
some very clever thinking went into supporting multiple numerical types,
and I want to acknowledge that. 🙇

Also, I took it as far as possible but that might not be the best
outcome, for example we might want to keep deserialization support. This
just demonstrates a possible direction we could go in.

---------

Co-authored-by: Andreas Gullberg Larsen <andreas.larsen84@gmail.com>
  • Loading branch information
Muximize and angularsen authored Feb 23, 2024
1 parent aeb0cd7 commit 1d644f8
Show file tree
Hide file tree
Showing 280 changed files with 3,761 additions and 8,973 deletions.
37 changes: 11 additions & 26 deletions CodeGen/Generators/NanoFrameworkGen/QuantityGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public struct {_quantity.Name}
/// <summary>
/// The numeric value this quantity was constructed with.
/// </summary>
private readonly {_quantity.ValueType} _value;
private readonly double _value;
/// <summary>
/// The unit this quantity was constructed with.
Expand All @@ -53,7 +53,7 @@ public struct {_quantity.Name}
/// <summary>
/// The numeric value this quantity was constructed with.
/// </summary>
public {_quantity.ValueType} Value => _value;
public double Value => _value;
/// <inheritdoc />
public {_unitEnumName} Unit => _unit;
Expand All @@ -66,7 +66,7 @@ public struct {_quantity.Name}
/// <param name=""value"">The numeric value to construct this quantity with.</param>
/// <param name=""unit"">The unit representation to construct this quantity with.</param>
/// <exception cref=""ArgumentException"">If value is NaN or Infinity.</exception>
public {_quantity.Name}({_quantity.ValueType} value, {_unitEnumName} unit)
public {_quantity.Name}(double value, {_unitEnumName} unit)
{{
_value = value;
_unit = unit;
Expand All @@ -79,29 +79,14 @@ public struct {_quantity.Name}
/// <summary>
/// Represents the largest possible value of {_quantity.Name}.
/// </summary>");

// Non decimal
Writer.WLCondition(_quantity.ValueType != "decimal", $@"
public static {_quantity.Name} MaxValue {{ get; }} = new {_quantity.Name}({_quantity.ValueType}.MaxValue, BaseUnit);
/// <summary>
/// Represents the smallest possible value of {_quantity.Name}.
/// </summary>
public static {_quantity.Name} MinValue {{ get; }} = new {_quantity.Name}({_quantity.ValueType}.MinValue, BaseUnit);
");

// Decimal MaxValue = 79228162514264337593543950335M
Writer.WLCondition(_quantity.ValueType == "decimal", $@"
public static {_quantity.Name} MaxValue {{ get; }} = new {_quantity.Name}(79228162514264337593543950335M, BaseUnit);
public static {_quantity.Name} MaxValue {{ get; }} = new {_quantity.Name}(double.MaxValue, BaseUnit);
/// <summary>
/// Represents the smallest possible value of {_quantity.Name}.
/// </summary>
public static {_quantity.Name} MinValue {{ get; }} = new {_quantity.Name}(-79228162514264337593543950335M, BaseUnit);
");
public static {_quantity.Name} MinValue {{ get; }} = new {_quantity.Name}(double.MinValue, BaseUnit);
Writer.WL($@"
/// <summary>
/// Gets an instance of this quantity with a value of 0 in the base unit Second.
/// </summary>
Expand Down Expand Up @@ -134,7 +119,7 @@ private void GenerateConversionProperties()
/// </summary>");
Writer.WLIfText(2, GetObsoleteAttributeOrNull(unit));
Writer.WL($@"
public {_quantity.ValueType} {unit.PluralName} => As({_unitEnumName}.{unit.SingularName});
public double {unit.PluralName} => As({_unitEnumName}.{unit.SingularName});
");
}

Expand All @@ -161,7 +146,7 @@ private void GenerateStaticFactoryMethods()
/// <exception cref=""ArgumentException"">If value is NaN or Infinity.</exception>");
Writer.WLIfText(2, GetObsoleteAttributeOrNull(unit));
Writer.WL($@"
public static {_quantity.Name} From{unit.PluralName}({_quantity.ValueType} {valueParamName}) => new {_quantity.Name}({valueParamName}, {_unitEnumName}.{unit.SingularName});
public static {_quantity.Name} From{unit.PluralName}(double {valueParamName}) => new {_quantity.Name}({valueParamName}, {_unitEnumName}.{unit.SingularName});
");
}

Expand All @@ -172,7 +157,7 @@ private void GenerateStaticFactoryMethods()
/// <param name=""value"">Value to convert from.</param>
/// <param name=""fromUnit"">Unit to convert from.</param>
/// <returns>{_quantity.Name} unit value.</returns>
public static {_quantity.Name} From({_quantity.ValueType} value, {_unitEnumName} fromUnit)
public static {_quantity.Name} From(double value, {_unitEnumName} fromUnit)
{{
return new {_quantity.Name}(value, fromUnit);
}}
Expand All @@ -190,7 +175,7 @@ private void GenerateConversionMethods()
/// Convert to the unit representation <paramref name=""unit"" />.
/// </summary>
/// <returns>Value converted to the specified unit.</returns>
public {_quantity.ValueType} As({_unitEnumName} unit) => GetValueAs(unit);
public double As({_unitEnumName} unit) => GetValueAs(unit);
/// <summary>
/// Converts this {_quantity.Name} to another {_quantity.Name} with the unit representation <paramref name=""unit"" />.
Expand All @@ -207,7 +192,7 @@ private void GenerateConversionMethods()
/// This is typically the first step in converting from one unit to another.
/// </summary>
/// <returns>The value in the base unit representation.</returns>
private {_quantity.ValueType} GetValueInBaseUnit()
private double GetValueInBaseUnit()
{{
return Unit switch
{{");
Expand All @@ -223,7 +208,7 @@ private void GenerateConversionMethods()
}};
}}
private {_quantity.ValueType} GetValueAs({_unitEnumName} unit)
private double GetValueAs({_unitEnumName} unit)
{{
if (Unit == unit)
return _value;
Expand Down
14 changes: 0 additions & 14 deletions CodeGen/Generators/NanoFrameworkGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,6 @@ public static void Generate(string rootDir, Quantity[] quantities, QuantityNameT
GenerateQuantity(quantity, Path.Combine(outputQuantities, $"{quantity.Name}.g.cs"));
GenerateProject(quantity, Path.Combine(projectPath, $"{quantity.Name}.nfproj"), versions);

// Convert decimal based units to floats; decimals are not supported by nanoFramework
if (quantity.ValueType == "decimal")
{
var replacements = new Dictionary<string, string>
{
{ "(\\d)m", "$1d" },
{ "(\\d)M", "$1d" },
{ " decimal ", " double " },
{ "(decimal ", "(double " }
};
new FileInfo(Path.Combine(outputDir, "Units", $"{quantity.Name}Unit.g.cs")).EditFile(replacements);
new FileInfo(Path.Combine(outputDir, "Quantities", $"{quantity.Name}.g.cs")).EditFile(replacements);
}

Log.Information("✅ {Quantity} (nanoFramework)", quantity.Name);
}
Log.Information("");
Expand Down
15 changes: 0 additions & 15 deletions CodeGen/Generators/QuantityJsonFilesParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ private static Quantity ParseQuantityFile(string jsonFileName)
?? throw new UnitsNetCodeGenException($"Unable to parse quantity from JSON file: {jsonFileName}");

AddPrefixUnits(quantity);
FixConversionFunctionsForDecimalValueTypes(quantity);
OrderUnitsByName(quantity);
return quantity;
}
Expand All @@ -63,20 +62,6 @@ private static void OrderUnitsByName(Quantity quantity)
quantity.Units = quantity.Units.OrderBy(u => u.SingularName, StringComparer.OrdinalIgnoreCase).ToArray();
}

private static void FixConversionFunctionsForDecimalValueTypes(Quantity quantity)
{
foreach (Unit u in quantity.Units)
// Use decimal for internal calculations if base type is not double, such as for long or int.
{
if (string.Equals(quantity.ValueType, "decimal", StringComparison.OrdinalIgnoreCase))
{
// Change any double literals like "1024d" to decimal literals "1024m"
u.FromUnitToBaseFunc = u.FromUnitToBaseFunc.Replace("d", "m");
u.FromBaseToUnitFunc = u.FromBaseToUnitFunc.Replace("d", "m");
}
}
}

private static void AddPrefixUnits(Quantity quantity)
{
var unitsToAdd = new List<Unit>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static class NumberTo{_quantityName}Extensions
continue;

Writer.WL(2, $@"
/// <inheritdoc cref=""{_quantityName}.From{unit.PluralName}(UnitsNet.QuantityValue)"" />");
/// <inheritdoc cref=""{_quantityName}.From{unit.PluralName}(double)"" />");

Writer.WLIfText(2, GetObsoleteAttributeOrNull(unit.ObsoleteText));

Expand Down
Loading

0 comments on commit 1d644f8

Please sign in to comment.