FormatStyle.measurement(): can only work for `UnitTemparature`, other type like `UnitMass` do not compile: Why overload not used?

// works or UnitTemparature` only:
Measurement(value: 26.7137, unit: UnitTemperature.celsius).formatted(.measurement())

// :( Instance method 'formatted' requires the types 'Measurement<UnitTemperature>.FormatStyle.FormatInput' (aka 'Measurement<UnitTemperature>') and 'Measurement<UnitMass>' be equivalent
Measurement(value: 54.783, unit: UnitMass.kilograms).formatted(.measurement())

There are two FormatStyle.measurement():

  1. for UnitTemparature: Apple Developer Documentation

  2. for UnitType: Dimension: Apple Developer Documentation

This is in Foundation source:

@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension FormatStyle {

    public static func measurement<UnitType>(width: Measurement<UnitType>.FormatStyle.UnitWidth, usage: MeasurementFormatUnitUsage<UnitType> = .general, numberFormatStyle: FloatingPointFormatStyle<Double>? = nil) -> Self where Self == Measurement<UnitType>.FormatStyle, UnitType : Dimension

    public static func measurement(width: Measurement<UnitTemperature>.FormatStyle.UnitWidth = .abbreviated, usage: MeasurementFormatUnitUsage<UnitTemperature> = .general, hidesScaleName: Bool = false, numberFormatStyle: FloatingPointFormatStyle<Double>? = nil) -> Self where Self == Measurement<UnitTemperature>.FormatStyle
}

The first .measurement() should be used for UnitMass but the compiler is not able to resolve to it?

Why cannot call the second one for UnitMass? Solving this here will probably solve my problem with generically format all Measurement of any UnitType

Edit: don't know why the built-in .measurement() overload is not found by the compiler. I can define my own .measurementXXX() to make things work:

import Foundation

extension FormatStyle {
    public static func measurementXXX<UnitType>(width: Measurement<UnitType>.FormatStyle.UnitWidth = .abbreviated, usage: MeasurementFormatUnitUsage<UnitType> = .general, numberFormatStyle: FloatingPointFormatStyle<Double>? = nil) -> Self where Self == Measurement<UnitType>.FormatStyle, UnitType : Dimension {
        .init(width: width, locale: Locale.autoupdatingCurrent, usage: usage, numberFormatStyle: numberFormatStyle)
    }
}
// works:
Measurement(value: 26.7137, unit: UnitTemperature.celsius).formatted(.measurementXXX())

// works:
Measurement(value: 54.783, unit: UnitMass.kilograms).formatted(.measurementXXX())

The error message isn't great, but if you look at those two overloads, you can see that the Dimension version requires a width, whereas the temperature defaults to .abbreviated. Whether or not this is intentional is something only Apple can answer.

3 Likes

:person_facepalming::pray: All the examples in the doc use UnitTemparature type and omits the width parameter. I just didn't see this difference.