Ruby Float#round behaviour change after update - ruby

I am upgrading a repository from Ruby version 2.3.3 to 2.5.1. A test is failing, and I have narrowed down the cause to the following behaviour:
In version 2.3.3
1.34875.round(4)
=> 1.3487
In version 2.5.1
1.34875.round(4)
=> 1.3488
Now, I'm aware of this change, but I don't think it's relevant because a) the default behaviour was left alone, and b) the observed change is opposite to the proposed change in the default. I'm also aware that floating point numbers are not a good way to accurately store finite decimals, and that some change in precision might explain why this change has occurred. But I don't know, and I don't know how to find out.

The behaviour you're describing sounds like https://bugs.ruby-lang.org/issues/13138, which was considered a bugfix and backported to 2.3.5. (I haven't confirmed which 2.4.x it was backported to, if any, but it was in trunk before 2.5.0.)
As you surmised, it is a precision issue. 1.34875's float representation is slightly less than 1.34875, so 2.3.3 does the overly-technically-correct thing and rounds down; newer versions recognise that rounding up is more consistent given that the float actually represents a range of values [including 1.34875].

The default behavior was not "left alone" as you suggest. There's new strategy to round to nearest even number: https://github.com/ruby/ruby/blob/8d7c380216809ba5bd4a3eec41d7dda61f825ffa/NEWS#core-classes-updates-outstanding-ones-only (search for round).
You can use
> 1.34875.round(4, half: :down)
=> 1.3487
To preserve what seems to be the behavior in 2.3.3.

Related

Maven Version Range To Exclude Next Minor Version

I am using Maven 3.3.3 and want to express that I will accept any 2.7.x version of the jackson-core dependency (but am not willing to go to 2.8.x until I've had a chance to assess for backward compatibility, run unit / regression tests, etc.).
This would allow my project to receive bug fixes (under incremental versions), but delay the jump to the next minor version until ready.
I instinctively wrote the following into pom.xml:
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>[2.7.1,2.8)</version>
However, a mvn dependency:list says that the following version is used:
com.fasterxml.jackson.core:jackson-core:jar:2.8.0.rc2:compile
I was taken aback by that, however dug up this answer which leads to the "official" Maven Javadoc which describes the sort order of Maven dependencies.
Those helped me understand why 2.8.0.rc2 is considered "older" than 2.8.0.
So, I reasoned that the following would (albeit hack-ishly) produce the desired results:
[2.7.1,2.8.0.a)
I was wrong. The dependency:list now produces:
com.fasterxml.jackson.core:jackson-core:jar:2.8.0:compile
Same result with (or variations with -a):
[2.7.1,2.8.a)
All together, this seems to imply the following orderings:
2.8.0 < 2.8.0.a
2.8.0.rc2 < 2.8.0
So ... if everything I learned in school about transitive relationships is correct, then:
2.8.0.rc2 < 2.8.0.a
That seems to contradict the SO answer. At the same time, the Javadoc is ambiguous (i.e. is the qualifier ordering listed the actually implemented ordering) and this Apache Wiki / Confluence page is mildly confusing.
Regardless, it doesn't seem to line up with either String sorting or common sense that a "Release Candidate" (assumed meaning for rc would precede an alpha version specified as a).
Would this be handled differently if there an actual 2.8.0-alpha version had been released?
Bottom line: is there a reasonably transferable way to specify a Maven Version Range which excludes everything in the 2.8.0 version space?
Edit: Even more bottom line... is there a clearly documented and publicly available description of the Maven version ordering algorithm outside of their source code? It's hard to tell if the cwiki page is a desired spec or implemented (and certainly doesn't go to the level of detail we're exploring here) and the Javadoc seems to imply (but isn't unambiguous in stating so) the equality between . and - which comments here demonstrate is not the case.
You can simply check the ordering by using the following command:
java -jar apache-maven-3.3.3/lib/maven-artifact-3.3.3.jar 2.8.0.rc2 2.8.0.a
Display parameters as parsed by Maven (in canonical form) and comparison result:
1. 2.8.0.rc2 == 2.8.0.rc-2
2.8.0.rc2 < 2.8.0.a
2. 2.8.0.a == 2.8.0.a
You can also check the other version 2.8.0-alpha via:
java -jar apache-maven-3.3.3/lib/maven-artifact-3.3.3.jar 2.8.0.rc2 2.8.0-alpha
Display parameters as parsed by Maven (in canonical form) and comparison result:
1. 2.8.0.rc2 == 2.8.0.rc-2
2.8.0.rc2 > 2.8.0-alpha
2. 2.8.0-alpha == 2.8-alpha
Maven itself says there is no official documentation until this bug is resolved.
Further, given what is stated in comments on the original question, I am concluding that there is no 100% safe, transferable of stating version numbers in a range for a more permanent solution.
Practically, I suppose making assumptions would render either of these valid for most uses:
[2.7.0,2.8.-alpha.alpha)
[2.7.0,2.7.9999.9999]
But theoretically, there could always be a smaller (in the first case) or larger (in the second) version number of the artifact (note that 2.7.9999.9999.9 > 2.7.9999.9999).
Even with those assumptions, stating the range in either manner leaves a build accepting any 2.7.x version published which might (for example) be 2.7.1-rc2.
I know realize this was an implied premise in my original question. That is, asking to "receive bug fixes (under incremental versions), but delay the jump to the next minor version until ready" assumed that the "incremental versions" are only non-alpha, non-rc, etc. versions.
That premise is invalid. Providing "only unqualified versions (eg. maj.min.inc with no -qualifer)" does not seem to be a use case supported by Maven and is a separate question entirely.
I think I'm now firmly in the "Maven Ranges are Evil" camp... not as much for build reproducibility reasons as much as being able to control the quality / finality of the included artifacts.

Why is twiddle wakka designed like this?

In the twiddle wakka ~> (aka pessimistic operator), why is it designed so that the tidle comes before the inequality? Since it includes the meaning >=, it is more consistent if it were >~. The ~> order makes it difficult to remember, and I often mistype it >~. It also makes me feel incorrectly that ~> 3.2 does not allow exactly 3.2. Is there a precursor to this symbol, or was it made up by a gem developer? Can someone come up with a way to make sense of this (even if that is not the original intention)?
Jim Weirich originally added the pessimistic operator to RubyGems as >* in this commit. He then changed it to ~> a few weeks later - the commit message includes an explanation:
Changed the pessimistic operator to "~>" (think approximately greater than).
Personally, I like that ~> is visually distinct from >=; if the operator was >~ instead, I think it would be easier to misread as >= when glancing at a Gemfile.

Emoji regression in ActiveSupport json output

I have found what I believe to be a regression in ActiveSupport 3.2.14. Here you can see the output of JSON.encode in ActiveSupport 3.2.13:
Here, in 3.2.14:
This is a breaking change for my use case and as a result I cannot upgrade to 3.2.14 without solving this. I believe this is the change that regressed my code.
Can someone with more experience in this area than I explain if this is by design, a regression, and why?
NOTE
If you want the raw text to run this line in your console, here is everything including the escaping for the emoji:
ActiveSupport::JSON.encode(["\360\237\230\204"])
I spoke with the author of the change to which I linked. He said while they are aware they have regressed emoji with this change, they are not considering a fix, and to upgrade to 4.0. Thus, I will not be upgrading to 3.2.14, or if I do, I will have to monkeypatch.

Converting stylesheet from XSLT 1.0 to 2.0

I have an xslt 1.0 stylesheet which needs to be converted to xslt 2.0.
I found this question here: Convert XSLT 1.0 to 2.0 which deals with the same issue.
According to that changing version attribute to 2.0 would do the trick. But is that the only thing which needs to be done?
Thanks in advance
I think the choice of strategy for conversion depends on how good a set of regression tests you have.
If you have a good set of regression tests, or if the consequences of introducing an error are not severe, then I would recommend the following steps:
(a) change the version attribute to 2.0
(b) run your test cases using an XSLT 2.0 processor and see if they work
(c) examine any test discrepancies and identify their cause (perhaps 80% of the time it will work correctly first time with no discrepancies).
If you don't have good tests or if you can't afford to take any risks, then you might need a more cautious strategy. (The ultimate in caution, of course, is the "don't change anything" strategy - stick with 1.0). Perhaps the best advice in this case is to start the conversion project by writing more test cases. At the very least, collect together a sample of the source documents you are currently processing, and the output that is generated for these source documents, and then use a file comparison tool to compare the output you get after conversion.
There are a few incompatibilities between 1.0 and 2.0; the one you are most likely to encounter is that xsl:value-of (and many other constructs) in 1.0 ignore all nodes in the supplied input sequence after the first, whereas XSLT 2.0 outputs all the nodes in the supplied sequence. There are two ways of dealing with this problem. Either (my recommendation) identify the places where this problem occurs, and fix them, usually by changing select="X" to select="X[1]"; or change the version attribute on the xsl:stylesheet back to version="1.0", which causes the XSLT 2.0 processor to run in backwards compatibility mode. The disadvantage of relying on backwards compatibility mode is that you lose the benefits of the stronger type-checking in XSLT 2.0, which makes complex stylesheet code much easier to debug.
In my experience the problems you encounter in conversion are more likely to depend on processor/implementation changes than on W3C language changes. Your code might be using vendor-defined extension functions that aren't supported in the 2.0 processor, or it might be relying on implementation-defined behaviour such as collating sequences that varies from one processor to another. I have seen code, for example, that relied on the specific format of the output produced by generate-id(), which is completely implementation-dependent.
"XSL Transformations (XSLT) Version 2.0", §J, "Changes from XSLT 1.0 (Non-Normative)" lists most the differences between XSLT 1.0 and XSLT 2.0 that you need to be aware of.

What are the constraints on Cocoa Framework version numbers?

We're distributing a Cocoa framework with regular updates. We'll be updating the version numbers with each release. The Apple documentation appears to suggest that version numbers should be consecutive incrementing integers. We are distributing output in several formats, and the framework is only one of them. We would rather not have to maintain a separate numbering system just for our frameworks.
We don't really care about the precise format of the version numbers of the framework, so long as they change whenever the product changes, and behave in a correct, sensible and expected manner. I'm looking for a way of avoiding having to run a separate version number counter.
One suggestion is that for product version 12.34.56 we could simply remove the dots and say the framework version is 123456 (with appropriate zero padding).
Is there a constraint on the type of number that can be represented (uint? long?)
Does it have to be a number? Could it be a string?
Do the numbers have to be consecutive?
Is there a standard way of doing things in this situation?
As I understand it, the reason for this requirement is so that you can have macro checks like:
#if FRAMEWORKNAME_VERSION >= 123456
// some stuff
#else
// some other stuff
#endif
The numbers do not need to be consecutive, and your suggested scheme is quite sensible:
#define MAKE_VERSION(MAJOR,MINOR,PATCH) ((MAJOR*10000)+(MINOR*100)+PATCH)
I would also suggest that in addition to defining a version, you also define constants for each version...
#define FRAMEWORKNAME_VERSION_1_0_0 MAKE_VERSION(1,0,0)
#define FRAMEWORKNAME_VERSION_1_0_1 MAKE_VERSION(1,0,1)
That way, you can check in multiple ways... either:
#if FRAMEWORKNAME_VERSION >= MAKE_VERSION(1,0,1)
// 1.0.1 and later
#else
// Before 1.0.1
#endif
Or:
#if defined(FRAMEWORKNAME_VERSION_1_0_1)
// 1.0.1 and later
#else
// Before 1.0.1
#endif
The key requirements that you should satisfy are:
The numbers are monotonically increasing
The numbers are predictable
The numbers are easily comparable
If you want to supply a string representation of your version in addition to the integer representation, by all means go ahead; however, I would strongly suggest that you have an integer representation available, as it simplifies comparison and allows the version to be checked in the preprocessor.

Resources