3 ms·
The one thing that’s bugging me about this is the particular JSON structures employed. They’ve gone for this: {"*operator*": [...args]} With one special cas
by chrismorgan 5y ago
The one thing that’s bugging me about this is the particular JSON structures employed. They’ve gone for this:
{"*operator*": [...args]}
With one special case:
{"*operator*": single_arg}
(This special case confirms that JsonLogic isn’t using arrays as a top-level construct, otherwise it’d be ambiguous. Well, it confirms either that or that it’s even worse-designed than it looks. Anyway, I’m going to assume arrays are free to use as a top-level construct.)
In short, you end up using an object and an array for each element. Yet the object is strictly being used as a two-tuple, and objects are a roundly bad idea for this application: the only way you’re ever going to be looking at it is “it’s an object, confirm that it has only one pair in it, then pull the first key out, and pull its value out”. This is quite inefficient in both memory and runtime performance. The only thing it really has going for it is that it guarantees that the key is a string, which is significantly overrated given the other more expensive bits of validation and access costs that it forces.
So the whole thing would be made more efficient (and arguably even more robust) by just changing it to an two-element array:
["*operator*", [...args]]
["*operator*", single_arg]
And then the natural next step is to say “why are we using two arrays rather than just one?” and flatten it into this:
["*operator*", ...args]
This is conveniently shorter to type, and eliminates the nasty single-argument special case too.
That’s very probably going to be more efficient on fixed-arity operators (which is most of them) and on potentially-unary operators, though it’s possible that it may be more expensive on larger calls if you need to slice the array during evaluation in order to exclude the operator.
So the end result I’ve suggested here is simpler, more consistent, smaller on the wire and in memory, faster, more robust across diverse languages and environments—in short, superior in pretty much every way. The only real place it might not be superior is auto-formatting, where you lose probable separation of arguments from operator (subjectively often desirable) but reduce the indentation level by one (more strongly desirable). It’s also more S-expressiony!