Provided that T is one of the supported types yes that does hold true (and is in the unit tests I have on the pending commit)
Sent from my iPhone > On Apr 20, 2017, at 11:29 AM, Martin R <martinr...@gmail.com> wrote: > > So is it correct to say that for all types T which NSNumber can hold (Double, > Float, Int, UInt, ... ) > > T(exactly: someNSNumber) > > will succeed if and only if > > NSNumber(value: T(truncating: someNSNumber)) == someNSNumber > > holds? > >>> On 20. Apr 2017, at 18:10, Philippe Hausler <phaus...@apple.com> wrote: >>> >>> >>> On Apr 19, 2017, at 6:09 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>> >>> >>> >>> On Wed, Apr 19, 2017 at 6:35 PM, Philippe Hausler <phaus...@apple.com> >>> wrote: >>>> >>>> >>>>> On Apr 19, 2017, at 16:17, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>>>> >>>>>> On Wed, Apr 19, 2017 at 6:00 PM, Philippe Hausler <phaus...@apple.com> >>>>>> wrote: >>>>>> >>>>>>> On Apr 19, 2017, at 3:23 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>>>>>> >>>>>>> On Wed, Apr 19, 2017 at 3:19 PM, Martin R <martinr...@gmail.com> wrote: >>>>>>>>> On 19. Apr 2017, at 01:48, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>>>>>>>> >>>>>>>>> So, as I understand it, `Float.init(exactly: Double.pi) == nil`. I >>>>>>>>> would expect NSNumber to behave similarly (a notion with which Martin >>>>>>>>> disagrees, I guess). I don't see a test that shows whether NSNumber >>>>>>>>> behaves or does not behave in that way. >>>>>>>> >>>>>>>> At present they behave differently: >>>>>>>> >>>>>>>> print(Float(exactly: Double.pi) as Any) >>>>>>>> // nil >>>>>>>> print(Float(exactly: NSNumber(value: Double.pi)) as Any) >>>>>>>> // Optional(3.14159274) >>>>>>>> >>>>>>>> I realize that identical behavior would be logical and least >>>>>>>> surprising. My only concern was about cases like >>>>>>>> >>>>>>>> let num = ... // some NSNumber from a JSON deserialization >>>>>>>> let fval = Float(exactly: num) >>>>>>>> >>>>>>>> where one cannot know how the number is represented internally and >>>>>>>> what precision it needs. But then one could use the truncating >>>>>>>> conversion or `.floatValue` instead. >>>>>>> >>>>>>> JSON numbers are double-precision floating point, unless I'm >>>>>>> misunderstanding something. If someone writes `Float(exactly: >>>>>>> valueParsedFromJSON)`, surely, that can only mean that they *really, >>>>>>> really* prefer nil over an imprecise value. I can see no other reason >>>>>>> to insist on using both Float and .init(exactly:). >>>>>> >>>>>> JSON does not claim 32 or 64 bit floating point, or for that matter 128 >>>>>> or infinite bit floating point :( >>>>> >>>>> >>>>> Oops, you're right. I see they've wanted to future-proof this. That said, >>>>> RFC 7159 *does* say: >>>>> >>>>>> This specification allows implementations to set limits on the range >>>>>> and precision of numbers accepted. Since software that implements >>>>>> IEEE 754-2008 binary64 (double precision) numbers [IEEE754] is >>>>>> generally available and widely used, good interoperability can be >>>>>> achieved by implementations that expect no more precision or range >>>>>> than these provide, in the sense that implementations will >>>>>> approximate JSON numbers within the expected precision. >>>>> >>>>> >>>>> So JSON doesn't set limits on how numbers are represented, but JSON >>>>> implementations are permitted to (and I'd imagine that all in fact do). A >>>>> user of a JSON deserialization library can rightly expect to know the >>>>> numeric limits of that implementation; for the purposes of bridging >>>>> NSNumber, if the answer is that the implementation parses JSON numbers as >>>>> double-precision values, Double(exactly:) would be the right choice; >>>>> otherwise, if it's 80-bit values, then Float80(exactly:) would be the >>>>> right choice, etc. >>>>> >>>> >>>> Float80 is not compatible with NSNumber; and is well out of scope for this >>>> proposal. >>> >>> OK, so Double is the largest floating point type compatible with NSNumber? >>> It stands to reason that any Swift JSON implementation that uses NSNumber >>> for parsed floating point values would at most have that much range and >>> precision, right? >> >> For JSONSerialization (which I am most familiar with and ships with >> Foundation); it can emit both NSNumbers and NSDecimalNumber. A rough >> approximation of the behavior: if it can store the value in an integer type >> it stores it as such in a NSNumber (iirc up to UINT64_MAX) and then if it >> has a decimal point it will attempt to parse as a double but if that is not >> enough storage it will store the best possible value into NSDecimalNumber. >> >> So NSNumber itself (excluding subclasses) can only store up to a 64 bit >> value. >> >>> >>> If so, then every floating point value parsed by any such Swift JSON >>> implementation would be exactly representable as a Double: regardless of >>> whether that specific implementation uses Float or Double under the hood, >>> every Float can be represented exactly as a Double. If a user is trying to >>> bridge such a NSNumber instance specifically to *Float* instead of Double, >>> and they are asking for an exact value, there's no a priori reason to think >>> that this user would be more likely to care only about the range and not >>> the precision, or vice versa. Which is to say, I don't think you'll get too >>> many bug reports :) >> >> In my mind there are two considerations here; balance against the surprise >> from new developers learning their first programming language versus >> consistency. In the end even if I believe the behavior is sub-par I would >> rather it be consistent. Primarily consistency is easier to teach even if it >> is derived from a standard developed with legacy behavior of C at its heart. >> >> Perhaps in the future we might want to eventually allow conversions to and >> from NSNumber via the Integer and FloatingPoint protocols; however I would >> guess that there needs to be a lot more thought and perhaps some >> modifications there to pull that off. Not to sound like a broken record, but >> again that it is out of scope for right now. >> >>> >>>>> >>>>>> After thinking about it more; it seems reasonable to restrict it to the >>>>>> behavior of Float(exactly: Double(…)). I am certain this will probably >>>>>> in the end cause more bugs for me to have to address and mark as >>>>>> “behaves correctly” and confuse a few new developers - but in the end >>>>>> they chose Swift and the consistent story would be the current behavior >>>>>> of Float(exactly: Double). >>>>>> >>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>>> On Tue, Apr 18, 2017 at 11:43 AM, Philippe Hausler >>>>>>>>>> <phaus...@apple.com> wrote: >>>>>>>>>> >>>>>>>>>>>> On Apr 18, 2017, at 9:22 AM, Stephen Canon <sca...@apple.com> >>>>>>>>>>>> wrote: >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>>> On Apr 18, 2017, at 12:17 PM, Joe Groff <jgr...@apple.com> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> On Apr 17, 2017, at 5:56 PM, Xiaodi Wu via swift-evolution >>>>>>>>>>>>> <swift-evolution@swift.org> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> It seems Float.init(exactly: NSNumber) has not been updated to >>>>>>>>>>>>> behave similarly? >>>>>>>>>>>>> >>>>>>>>>>>>> I would have to say, I would naively expect "exactly" to behave >>>>>>>>>>>>> exactly as it says, exactly. I don't think it should be a synonym >>>>>>>>>>>>> for Float(Double(exactly:)). >>>>>>>>>>>>> On Mon, Apr 17, 2017 at 19:24 Philippe Hausler via >>>>>>>>>>>>> swift-evolution <swift-evolution@swift.org> wrote: >>>>>>>>>>>>> I posted my branch and fixed up the Double case to account for >>>>>>>>>>>>> your concerns (with a few inspired unit tests to validate) >>>>>>>>>>>>> >>>>>>>>>>>>> https://github.com/phausler/swift/tree/safe_nsnumber >>>>>>>>>>>>> >>>>>>>>>>>>> There is a builtin assumption here though: it does presume that >>>>>>>>>>>>> the swift’s representation of Double and Float are IEEE >>>>>>>>>>>>> compliant. However that is a fairly reasonable assumption in the >>>>>>>>>>>>> tests. >>>>>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> Even with the updated code at >>>>>>>> https://github.com/phausler/swift/tree/safe_nsnumber >>>>>>>> >>>>>>>> print(Double(exactly: NSNumber(value: Int64(9000000000000000001))) >>>>>>>> as Any) >>>>>>>> // Optional(9e+18) >>>>>>>> >>>>>>>> still succeeds, however the reason seems to be an error in the >>>>>>>> `init(exactly value: someIntegerType)` inititializers of Float/Double, >>>>>>>> I have submitted a bug report: https://bugs.swift.org/browse/SR-4634. >>>>>>>> >>>>>>>> >>>>>>>>>>>> (+Steve Canon) What is the behavior of Float.init(exactly: >>>>>>>>>>>> Double)? NSNumber's behavior would ideally be consistent with that. >>>>>>>>>>> >>>>>>>>>>> The implementation is essentially just: >>>>>>>>>>> >>>>>>>>>>> self.init(other) >>>>>>>>>>> guard Double(self) == other else { >>>>>>>>>>> return nil >>>>>>>>>>> } >>>>>>>>>>> >>>>>>>>>>> i.e. if the result is not equal to the source when round-tripped >>>>>>>>>>> back to double (which is always exact), the result is nil. >>>>>>>>>>> >>>>>>>>>>> – Steve >>>>>>>>>> >>>>>>>>>> Pretty much the same trick inside of CFNumber/NSNumber >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution