Is there a way to mark with @available(*, deprecated, message:) methods generated by compiler without manual reimplementation of them?
I have several large structs that conform to Hashable. This is needed for diffable algorithms and keeping them in Set<> or Dictionary. But it is not correct for programmers to directly compare two instances via == because of some reasons.
Possible solution is to mark such method as @available(*, deprecated, message: "some message that guide user"), but it requires to implement manually == function, which is error prone.
This doesn’t answer your question, but if you are manually implementing Hashable then you should also be manually implementing Equatable to match.
On the other hand, if your Hashable conformance is synthesized, I am having difficulty imagining why the synthesized Equatable conformance is problematic.
aside: @available(*, deprecated) is probably not what you want here, this is for things that change between releases. but it sounds like ==(_:_:) was never valid to begin with.
It is a typical task to use it as key in Dictionary<AmountValue, _>, but it is not legal to compare them via ==, instead isAlmostEqual(to:) method should be used.
these are structs backed with float point numbers, and it is not safe and correct to make all kind of operations. Like with Clock.Instant and Duration
these are structs with a large numbers of fileds, which are made Hashable for using in diffable datasources. But it is not valid to compare them with ==. Typical mistake that users do is trying to find an element in collection by comparing instances with ==. Instead, they should compare instance's IDs.
So what I need is to keep structs Hashable, but prevent users from comparing via ==.
Yes, it is. I mean public Interface of Duration or Clock.Instant doesn't allow all math operations, only subset of them is possible. AmountValue is designed in a similar manner.
these things tend to be money-like in the sense that they have fixed increments, eg. 0.001 lbs. Double is for when you want to represent things that have wildly different magnitudes, like if you wanted to represent 1,000,000,000,000 lbs and 0.0000001 lbs in the same schema. so unless you are doing that, Double is probably the wrong tool for the job.
i’ve long wished swift had modern decimals. but sadly it does not. (this probably isn’t very helpful, i know.)
this is a different problem than the “large structs = slow equality” problem you mentioned earlier:
my non-actionable advice is to use a proper decimal type to model the product quantity. but this type doesn’t exist, we only have NSDecimal. arggghhh!!
OK, but if it's not "legal" to compare them with ==, then it's also a programming error to put them in a dictionary, because Dictionary compares them with == internally.
Using a decimal type or not does nothing to change this situation; generally speaking if you should be comparing with a tolerance when using binary floating-point, you should also be comparing with a tolerance when using decimal floating-point or integers for the same computation.
You can construct trivial examples where one happens to work out "correctly" and the other does not, but these are not the norm, and code that assumes such behavior is buggy code.
Increment step is get from server, it is not a constant. And it is a float point number. Double suites well as a back-value of AmountValue .
I wish it too.
This is not the only problem. Another one is that comparing them via == is logically incorrect. The should be compared by InstanceID, like class are compared via === which is not the same as ==.
That's why we use Double for now. Decimal is more suitable but currently is inconvenient in use, and for our tasks there is not so much benefits of using it.
i don’t think this is true at all, if you are using decimals instead of binary floating point, it is probably because you care about exactness. e.g. an account balance either matches exactly, or it doesn’t match at all. interpreting $1.000001 as equivalent to $1.000000 is a very fast way to go bankrupt.
Right. Which is why you would not compare with a tolerance, whether you were using Double or a decimal type or UInt64 or anything else. If it's appropriate to use a tolerance with one, it is appropriate to use a tolerance with the other. If not, it is not appropriate in either case.
are you downloading binary protos? because if you are downloading JSON (or some other text-based serialization format), the JSON is probably encoding a decimal, not a binary float.
I know that Dictionary compares them with == internally, and it is totally correct. But this should not be done in app logic. We can get from server two almost equal values: "5.4999999999999991118215802999" and "5.5000000000000008881784197001". In app logic we should treat them as almost equal. Lats say it is a quantity of bananas user wants to buy. In user cart we have "5.4999999999999991118215802999", but in another response server returned us "5.5000000000000008881784197001". Comparing them with == is a programmer's error.
Finally, in app logic we should use special math and compare funcs, but for Hashability == should be used.
In this case do you want two Set elements / dictionary keys or just one? If just one – then you'd not want to use those values as is as set elements / dictionary keys.
Also not, that generally it's not safe to use Floating point numbers as Set elements / dictionary keys –because of NaN's that always compare false.
One possible workaround would be to use fixed point numbers in this case to sidestep the whole issue.
As I wrote in example AmountValue can only be constructed if rawValue .isNormal || .isZero, .sign == .plus, so NaN is impossible.
So I agree generally it's not safe. But after all checks and validation it is.
Which one? Decimal is not suitable as I wrote.
To be focused: float point value that is used as underlying value is not a problem.
The real task is to make possible only special math and compare funcs and impossible to use < > == because it is a programmer error, no matter what underlying type is. For Hashability == should be used.