[Preview Discussion] Argument Coercion Proposal #2
Replies: 4 comments 25 replies
-
Note: Going forward, I think that proposals should be presented in JSON Blocks, [
"Basic Tests",
{
"description": "Adds two numbers together",
"rule": { "+": [1, 2] }
"result": 3,
"data": {}
}
] Format outlined here: https://github.com/json-logic/.github/blob/main/TEST_FORMAT.md To make it easier to extract and play with. Here are some of the proposed behaviors: [
"# These are tests from https://github.com/orgs/json-logic/discussions/2",
{
"description": "Standard Max",
"rule": { "max": [1, 2, 3] },
"data": {},
"result": 3
},
{
"description": "Standard Max, Single Argument Sugared",
"rule": {"max": 1},
"data": {},
"result": 1
},
{
"description": "Max with Logic Chaining",
"rule": { "max": {"var": "data"} },
"data": { "data": [1, 2, 3] },
"result": 3
},
{
"description": "Cat with Logic Chaining",
"rule": {
"cat": {
"merge": [ ["Hello "], ["World", "!"] ]
}
},
"data": {},
"result": "Hello World!"
},
{
"description": "Cat with Logic Chaining (Simple)",
"rule": { "cat": {"var": "text"} },
"data": { "text": ["Hello ", "World", "!"] },
"result": "Hello World!"
},
{
"rule": {
"max": {
"map": [
{
"filter": [
{"var": "people"},
{
"===": [ {"var": "department"}, "Engineering" ]
}
]
},
{"var": "salary"}
]
}
},
"data": {
"people": [
{"name": "Jay Ortiz" , "salary": 100414, "department": "Engineering"},
{"name": "Louisa Hall" , "salary": 133601, "department": "Sales" },
{"name": "Kyle Carlson" , "salary": 139803, "department": "Sales" },
{"name": "Grace Ortiz" , "salary": 147068, "department": "Engineering"},
{"name": "Isabelle Harrington", "salary": 112704, "department": "Marketing" },
{"name": "Harold Moore" , "salary": 125221, "department": "Sales" },
{"name": "Clarence Schultz" , "salary": 127985, "department": "Sales" },
{"name": "Jesse Keller" , "salary": 149212, "department": "Engineering"},
{"name": "Phillip Holland" , "salary": 105888, "department": "Marketing" },
{"name": "Mason Sullivan" , "salary": 147161, "department": "Engineering"}
]
},
"result": 149212,
"description": "Max with Logic Chaining (Complex)"
}
] |
Beta Was this translation helpful? Give feedback.
-
@json-logic/core Hey folks, this is a "test" proposal to solicit feedback on the best way to organize proposals. I do think that each proposal should have the relevant JSON attached. If y'all have suggestions on how to organize proposals going forward, we can definitely incorporate that into the initiative's guidelines |
Beta Was this translation helpful? Give feedback.
-
I think part of the confusion is that you're trying to solve two problems simultaneously. Separate the chaining from the "sugaring adjustment". { "cat": { "var": "text" } } I propose that there be a two step process.
This means that The obvious gotcha is how to retain an array in the data as a single value. The answer is to require that it explicitly contained in an array. { "cat": [{ "var": "text" }] } This kind of thing is done all the time in other syntaxes and languages, where the shorthand can only be used in specific cases, and for other scenarios the full syntax MUST be used. For example, in RFC 9535 (JSON Path), the dot -syntax for a property selector ( It's perfectly acceptable to have cases where the sugaring can't be used as long as we can specify it well, and I think we can in this case. |
Beta Was this translation helpful? Give feedback.
-
And maybe I'll explain it in one more way (though I'll be repeating some things): Right now, traversed arguments are passed to methods with the following rule:
Imagine With the current rule, given data is
I'd like to adjust this slightly, and I believe it would be a backwards compatible change because this is not done very often. I'd like to switch the rule to This tweak also passes every test in the public test suite. With the proposed rule, given data is
This would make it significantly easier to chain logic together, so you could call |
Beta Was this translation helpful? Give feedback.
-
Hey folks 👋🏻
We still need to set community guidelines and set up a process and repository for presenting proposals.
I wanted to bring up one item a bit early that I feel might be controversial and may not end up being adopted. I fully expect to lose, but I hope that I'll be able to convice 😉
Background
So, to get things started, let's establish some background, JSON Logic is basically an AST / serializable S-Expressions in JSON.
To call a method, you use a key in an object, and the value is treated as your arguments for the expression.
Is conceptually the same as calling
max(1, 2, 3)
So far so good.
Per mainline JSON Logic, when you call a method directly a value, this is treated as shorthand for calling with a single argument array.
Therefore,
{ "max": 1 }
is the same as{ "max": [1] }
, which translates tomax(1)
This is also fairly reasonable, though has caused some confusion with
{ "not": 0 }
vs{ "not": [0] }
. Both of these expressions should translate tonot(0)
because of the shorthand sugaring; but I ultimately believe this design decision makes sense, and I believe needs to be preserved.Proposal
Where I diverge slightly is in how I wish to treat chained logic statements.
Imagine I have
{"max": {"var": "data"} }
and{ "data": [1, 2, 3] }
If we treat chained logic the same way as values, we limit our capabilities significantly, or make operator implementation quite a bit more complex.
For example, if
{"max": {"var": "data"} }
is interpreted as{"max": [{"var": "data"}] }
, it would be equivalent tomax([1, 2, 3])
instead ofmax(1, 2, 3)
, which unless we create a rather robust implementation ofmax
, would likely return awkward results.Similarly, if I had
{ "cat": { "merge": [["Hello "], ["World", "!"]] } }
, cat would receive[["Hello ", "World", "!"]]
as its argument list.In
json-logic-js
, this ends up producing"Hello ,World,!"
as it automatically callstoString
on the array..What if Instead of the sugaring operation mentally being
(x is not array) ? [apply x] : apply x
, the sugaring operation could instead beconcat([], apply x)
.Then we'd be able to chain function calls and essentially treat them as if they spread into the argument list, so if I say:
With the data
It will result in
Hello World!
So instead of
{ "cat": { "var": "text" } }
being automatically sugared into{ "cat": [{ "var": "text" }] }
ascat([var("text")])
, it's instead parsed ascat(...var("text"))
Making it possible to do things like:
With the following data:
And output
149212
Arguments Against
I believe a solid argument against this proposal is that it diverges significantly from the current mental model for the sugaring operation.
concat([], apply x)
is a bit more advanced of an operation to deal with sugaring.Arguments For
This approach would make JSON Logic significantly more flexible and capable.
It'd be easy to pass the output of a
filter
&map
statement intocat
or+
and have it produce a reasonable result.It also provides this capability without embedding a ton of edge cases into each operator to be able to support "If I receive a single argument, and that argument is a list"
It's also still the same operation, it just changes when the "is array" evaluation occurs by one step.
Backwards Compatibility
I don't believe this tweak would break anyone's existing logic; and I believe that this would enable use-cases that otherwise would not be possible.
Beta Was this translation helpful? Give feedback.
All reactions