> 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 > <mailto:phaus...@apple.com>> wrote: > > >> On Apr 19, 2017, at 16:17, Xiaodi Wu <xiaodi...@gmail.com >> <mailto:xiaodi...@gmail.com>> wrote: >> >> On Wed, Apr 19, 2017 at 6:00 PM, Philippe Hausler <phaus...@apple.com >> <mailto:phaus...@apple.com>> wrote: >> >>> On Apr 19, 2017, at 3:23 PM, Xiaodi Wu <xiaodi...@gmail.com >>> <mailto:xiaodi...@gmail.com>> wrote: >>> >>> On Wed, Apr 19, 2017 at 3:19 PM, Martin R <martinr...@gmail.com >>> <mailto:martinr...@gmail.com>> wrote: >>>> On 19. Apr 2017, at 01:48, Xiaodi Wu <xiaodi...@gmail.com >>>> <mailto: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 >>>> <mailto:phaus...@apple.com>> wrote: >>>> >>>>> On Apr 18, 2017, at 9:22 AM, Stephen Canon <sca...@apple.com >>>>> <mailto:sca...@apple.com>> wrote: >>>>> >>>>>> >>>>>> On Apr 18, 2017, at 12:17 PM, Joe Groff <jgr...@apple.com >>>>>> <mailto:jgr...@apple.com>> wrote: >>>>>> >>>>>> >>>>>>> On Apr 17, 2017, at 5:56 PM, Xiaodi Wu via swift-evolution >>>>>>> <swift-evolution@swift.org <mailto: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 <mailto: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 >>>>>>> <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 >>> <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 >>> <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