ietf-wg-jsonpath / draft-ietf-jsonpath-base

Development of a JSONPath internet draft
https://ietf-wg-jsonpath.github.io/draft-ietf-jsonpath-base/
Other
58 stars 20 forks source link

Clarification of some aspects of function expressions #423

Closed goessner closed 1 year ago

goessner commented 1 year ago

These questions/hurdles/nits came up while reading PR #420 and related issues/PR's carefully.

goessner commented 1 year ago

In Type System for Function Expressions (L-1473)

{{tbl-types}} defines the available types in terms of abstract instances, where n denotes a node, v denotes a value, and nl denotes a nodelist.

That 'n' for node seems to be used nowhere else.

goessner commented 1 year ago

Example (L-1552)

$[?length(@.authors) >= 5]

What, if function length returns Nothing? Is Nothing >= 5, is it a comparable?

goessner commented 1 year ago

Example (L-1581)

$[?count(@.*.author) >= 5]

What is the return type, if the NodesType argument is Nothing?

goessner commented 1 year ago

Nit (L-1650)

The "value" function extension provides a way to convert a instance of NodesType ...

... 'an instance' ...

goessner commented 1 year ago

Consider

$[?value(@..angle) > 3.14]

What is the result, if the return value of value is Nothing?

Shouldn't I always guard this by

$[?count(@..angle) == 1 && value(@..angle) > 0]

I think, I always would.

goessner commented 1 year ago

If I, as a non-implementer of JSONPath, would like to register a function, say ...

nl taking a NodesType as single argument and returning an array of normalized pathes or Nothing

... I would need to know the implementation specific shape of NodesType and Nothing.

As a consequence of this only implementers can register (or implement already registered) functions, as long as they didn't document internal aspects of NodesType and Nothing.

If we do not want such a scenario, how could we achieve an implementation-independent interface (types) for functions?

cabo commented 1 year ago

In Type System for Function Expressions (L-1473)

{{tbl-types}} defines the available types in terms of abstract instances, where n denotes a node, v denotes a value, and nl denotes a nodelist.

That 'n' for node seems to be used nowhere else.

Yep, this is a remnant. Fixed in e6dc704

cabo commented 1 year ago

Example (L-1552)

$[?length(@.authors) >= 5]

What, if function length returns Nothing? Is Nothing >= 5, is it a comparable?

length Is declared as a ValueType, so it is well-typed as a comparable. Section Comparisons says:

The comparison operators == and < are defined first and then these are used to define !=, <=, >, and >=.[¶](http://127.0.0.1:7999/#section-2.5.5.2.2-1)

Then it goes on to say:

When either side of a comparison results in an empty nodelist or Nothing:

a comparison using the operator == yields true if and only the other side also results in an empty nodelist or Nothing.
a comparison using the operator < yields false.

So == is false (5 is not Nothing), and < also is false.

Finally, it says:

The comparison a >= b yields true if and only if b < a yields true or a == b yields true.[¶](http://127.0.0.1:7999/#section-2.5.5.2.2-8.4)

Since neither is the case, the answer is that the comparison is false.

cabo commented 1 year ago

Example (L-1581)

$[?count(@.*.author) >= 5]

What is the return type, if the NodesType argument is Nothing?

NodesType does not have Nothing as a special value; this would be an empty nodelist. Count

gives the number of nodes in the nodelist.

so it returns 0 on this case, as there is no (0) node in the nodelist.

cabo commented 1 year ago

Nit (L-1650)

The "value" function extension provides a way to convert a instance of NodesType ...

... 'an instance' ...

Fixed in ff5f2a3

cabo commented 1 year ago

Consider

$[?value(@..angle) > 3.14]

What is the result, if the return value of value is Nothing?

When either side of a comparison results in an empty nodelist or Nothing:
[...]
a comparison using the operator < yields false.

Shouldn't I always guard this by

$[?count(@..angle) == 1 && value(@..angle) > 0]

I think, I always would.

That is a matter of style, and I don't disagree with being explicit. value() still has to have a defined value as we don't have short-circuiting in JSONPath.

cabo commented 1 year ago

If I, as a non-implementer of JSONPath, would like to register a function, say ...

nl taking a NodesType as single argument and returning an array of normalized pathes or Nothing

... I would need to know the implementation specific shape of NodesType and Nothing.

You can register it right away, but then you need to get the new function extension into implementations.

JSONPath does not provide a way to define your own functions, so indeed, you'll have to wait for implementers.

An expression language that allows to define functions in-language would be an interesting project, but probably going beyond what we can do here.

As a consequence of this only implementers can register (or implement already registered) functions,

No/Yes, see above.

as long as they didn't document internal aspects of NodesType and Nothing.

This type and this value are well-defined, so describing them in a registration should pose no problems.

If we do not want such a scenario, how could we achieve an implementation-independent interface (types) for functions?

I'm having a hard time imagining such an interface. It would need to be different for different platforms, and for different strategies for implementing JSONPath on such a platform. So it would, for all intents and purposes, be implementation dependent. Unless/Until we define the abovementioned powerful expression language.

cabo commented 1 year ago

nl taking a NodesType as single argument and returning an array of normalized pathes or Nothing

Oh, and remember that we are still in the filter selector expression mechanism, so it is not clear that such a function extension would be particularly useful. Adding Projection/Transformations to JSONPath is another interesting project that goes beyond base.

goessner commented 1 year ago

@cabo : thanks for clarification of all ...

glyn commented 1 year ago

I believe the required changes were covered by https://github.com/ietf-wg-jsonpath/draft-ietf-jsonpath-base/pull/420. Please re-open if this is not the case.

gregsdennis commented 1 year ago

JSONPath does not provide a way to define your own functions, so indeed, you'll have to wait for implementers.

JSON Path may not provide this, but the more user-friendly implementations likely will (mine does). So you can register your function, then go on to implement the function and plug it in.

cabo commented 1 year ago

Indeed, it should not be too hard to do this for any single implementation (my PoC implementation currently doesn't, because I didn't need to prove that particular concept :-), but it will). Defining a way to do this across implementations, in a "standard" way, is much harder.

gregsdennis commented 1 year ago

Defining a way to do this across implementations, in a "standard" way, is much harder.

I don't think we need to define it. We can just state something like,

Implementations SHOULD provide a mechanism for the user to provide their own algorithms for function extensison

or some such. The wording isn't great.

We would need to be careful to not open the door for arbitrary custom functions (although implementations can still do that if they want; it just wouldn't be spec-sanctioned).