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

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

Avoid type conversion language #405

Closed glyn closed 1 year ago

glyn commented 1 year ago

I intend to attempt to build on the merge of #403 with an editorial change (i.e. no syntactic or semantic impact) to avoid the use of type conversion language. The aim is to make the spec clearer, but we can judge the success of that once I've made the attempt.

See https://github.com/ietf-wg-jsonpath/draft-ietf-jsonpath-base/pull/403#pullrequestreview-1308453021 and the following short thread for context.

gregsdennis commented 1 year ago

@glyn can you please explain your objection to the conversions? I think they're perfectly clear. (I'm biased as I wrote it.) But you seem opposed to the idea of them rather than how they're specified.

Type conversions are a necessary mechanic for comparisons. I haven't seen a language that doesn't employ conversions in some way.

Even Javascript, a notoriously loosely typed language, has them. Consider "42" == 42. Javascript allows you to do this, and it will return true, but under the hood it's still doing a type conversion. Whether it attempts to convert the string to a number or the number to a string, it MUST do some kind of conversion on one or both of the values before comparing the values in order for this to return true.

gregsdennis commented 1 year ago

I'd like to explore this by expressing @.a && @.b == 42 functionally, without "conversion" language.

Thus, we would write the expression functionally as

both(@.a, equals(@.b, 42))

Except we have a type mismatch because @.a and @.b are NodesType, so these functions are not receiving the right types of parameters.

To fix this, we'll need LogicalType and ValueType from those NodesTypes, so let's introduce new functions (as @cabo suggested in https://github.com/ietf-wg-jsonpath/draft-ietf-jsonpath-base/issues/404#issuecomment-1440291255):

Now we can write the functional version as

both(logical(@.a), equals(value(@.b), 42))

All of the types align, and this can be executed.

Now, let's remove the first two functions to get back to the expression syntax:

logical(@.a) && value(@.b) == 42

All of the types align, and this can still be evaluated.

Now, the really interesting part is that we can infer from the context of the original expression that @.a needs to be wrapped by logical() and @.b needs to be wrapped in value() because @.a and @.b are not the right type for those locations in the expression.

Therefore we can say that the logical() and value() functions can be called implicitly, allowing us to remove the function calls from the syntax, giving us back the original expression:

@.a && @.b == 42

I (and I suspect most developers) would call logical() and value() "conversion functions," but if you want to specify what's going on as I've laid out above, I'm okay with that. Instead of implicit conversions, we have implicit function calls. I'd argue that conversions are more common and therefore easier to understand.

cabo commented 1 year ago

Don't call it "logical()", but call it "exists()" -- this is a very specific function that we just have decided to make the default conversion.

gregsdennis commented 1 year ago

Don't call it "logical()", but call it "exists()" -- this is a very specific function that we just have decided to make the default conversion.

"exists" doesn't convey what's happening. Maybe "nodeExists" or "isNotEmpty" or "containsNode," but not just "exists." An empty nodelist "exists."

Secondly, while "logical" may not be appropriate for the spec, it does help to explain what's really happening.

cabo commented 1 year ago

"exists" doesn't convey what's happening.

Neither do length, count, match or search, or pretty much any other function name that I have found in a programming language. You just learn these things.

Maybe "nodeExists" or "isNotEmpty" or "containsNode," but not just "exists." An empty nodelist "exists."

I maintain that "exists" is the best way to name this function.

My point is that this is not a "conversion", but an actual processing function, that we just happen to have made implicit in the non-function grammar and therefore may have wanted to mirror on the function side.

This is in contrast to "value", which is very much a conversion, just unpacking something (and checking that this is deterministic).

gregsdennis commented 1 year ago

Neither do length, count, match or search

I think these convey what they're doing better than exists. But I'm not going to be fussy on naming.

My point remains that implicit conversions (or function calls if you prefer) do occur, even if we don't think they do.

glyn commented 1 year ago

I am going to wait for #404 to be addressed before progressing this issue (as the solution to #404 may affect the type conversions required).

gregsdennis commented 1 year ago

I am going to wait for #404 to be addressed before progressing this issue (as the solution to #404 may affect the type conversions required).

Nope, you can't. I already claimed in that issue that this issue needed to be resolved first. I win 😆.

cabo commented 1 year ago

I marked this has-PR because #410, if it is the way we want to go, would resolve this issue.

glyn commented 1 year ago

It seems like we are going to need type conversions in some shape or form, even if we don't call them that. Closing.