01mf02 / jaq

A jq clone focussed on correctness, speed, and simplicity

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

range(0; infinite)

pkoppstein opened this issue · comments

Currently this jq idiom won't work in jaq because range requires its args to be integers. Although for practical purposes range(0; infinite|floor) could typically be used, it's not the same thing because infinite|floor is finite (which seems a bit problematic in itself, by the way), so it would be nice if jaq could make an exception for infinite when presented as an argument to range.

Of course 0|repeat(.+1) could be used but that, it seems to me, lacks the convenience, familiarity and clarity of range.

I am feeling against this. I tried to put my reasoning into the README:

The filter range(m; n) constructs a sequence of numbers m, m+1, ...,
where any number must be smaller than n.
In jq, m and n can be floating-point numbers, whereas
in jaq, m and n must be integers.
This is to avoid potential numerical stability problems.
That means that unlike in jq, you cannot use
range(m; infinite) to generate the infinite sequence m, m+1, ....
However, you can use m | recurse(.+1) to achieve the same in jaq.

The point is potential numerical stability problems. Accepting floating-point numbers as arguments to range is of course convenient for users, because they can just write range(0; infinite). In jq, this is not a problem, because every number is floating-point. But in jaq's model, this does not make sense, because what numbers will this yield? Floating-point or integer numbers? Given that infinite is clearly floating-point, this would make the whole sequence floating-point, which would be rather unexpected. Of course, we could just introduce a little exception here, as you suggest. But I think that each exception, as convenient as it might look at first, bears potential for a later WTF moment. jq has many WTF moments, and given that I want to avoid these as much as possible with jq, I opt for strictness over convenience here. I hope you understand. :)

@01mf02 wrote:

I am feeling against this.

I hope, therefore, that once I've addressed all your concerns as I think I can do, you will reopen this issue.

The main point is that you have read much too much into this ER. For range/2, the request is only for range(X; infinite), where X is an integer, to be allowed. Thus your concerns about numerical stability in particular all vanish.

I'd also point out that there is nothing in JSON to indicate whether infinite should be regarded as a "float" or an "integer" or something else. In jq, we have some predicates like isinfinite, but there is nothing to require that infinite be regarded as a float. (Agreed, infinite is pretty-printed as a float, but that's no more indicative than that nan pretty-prints as null.)

Agreed, surprises are to be avoided where possible, but the main surprise here is that range(0; infinite) is disallowed. As mentioned, both jq and gojq allow it (and gojq DOES make a sharp distinction between integers and floats).

(The secondary surprise of course is that infinite|floor evaluates to an integer, but I am not sure what would work best for jaq - should infinite|floorevaluate to nan or raise an error, or ...?)

Hope you enjoyed your vacation!

@pkoppstein, I am happy to tell you that by cb743ef, the range filter is implemented by definition, which will make range(n; infinite) work as you described.

@01mf02 - Thanks for letting me know! Needless to say I'm also very glad that you didn't let the trees prevent you from seeing the forest!!!