IBM / JSONata4Java

Open Source Java version of JSONata
Apache License 2.0
88 stars 36 forks source link

can not pass an array of functions into higher order function like map #268

Closed cuichenli closed 1 year ago

cuichenli commented 1 year ago

Following is the code I tried:

(
  $returnTrue := function() {
      true
  };

  $returnFalse := function() {
      false
  };
  $flist := [$returnTrue, $returnFalse];

  $map($flist, function($ff) {
      $ff()
  })
)

It works correctly on https://try.jsonata.org/ as following: image

But it won't work with JSONata4Java as following: image

wnm3 commented 1 year ago

This works. Note the parentheses after the function calls in $flist: ( $returnTrue := function() { true }; $returnFalse := function() { false }; $flist := [$returnTrue(), $returnFalse()]; $map($flist, function($v){$v} ))

This also works: ( $returnTrue := function() { true }; $returnFalse := function() { false }; $flist := [$returnTrue(), $returnFalse()]; $map($flist, function($ff){$ff} ))

If you agree, please close this issue.

wnm3 commented 1 year ago

The problem is, without the parentheses, we interpret the $returnTrue to be a variable reference and not a function call.

wnm3 commented 1 year ago

Another problem is the language we use defined a variable as the $ID without parentheses, so the reference to $returnTrue (or $returnFalse) in the flist array sees them as variables, and variable recall wants to retrieve a JsonNode, not a function. The way this is working in jsonata.org is the $flist is an array of functions (hence the need to provide the parentheses for $ff in the map's function).

I implemented a patch that executes a reference to a function declared as a variable (as in the flist declaration) but the problem is it attempts to execute the function at the time the variable is referenced (e.g., when creating the flist array). So with the patch you can execute:

( $returnTrue := function() { true }; $returnFalse := function() { false }; $flist := [$returnTrue, $returnFalse]; $map($flist, function($ff){$ff} ))

e.g,. without needing the parentheses for the $returnTrue, $returnFalse parameters.

But this isn't a very good solution IMHO.

You can try this by adding these lines in the ExpressionVisitor starting after line 3030: JsonNode result = getVariable(varName);

        if (result == null) {
          // see if this is calling a declared function with no parameters
          DeclaredFunction declFct = getDeclaredFunction(varName);
          if (declFct != null) {
            ExprListContext exprListCtx = declFct.getExpressionList();
            result = visit(exprListCtx);
          }
        }

The reason I don't like this solution is it would only work for functions that have no parameters, and the existing code would work if you added parentheses when referencing the functions in flist.

Perhaps I need more details about the real use case to appreciate what you are trying to accomplish.

cuichenli commented 1 year ago

Perhaps I need more details about the real use case to appreciate what you are trying to accomplish.

there is no actual use case for it - i report it mainly due to the inconsistency i noticed between jsonata4java and jsonata.org (along with #267 ). and i think the workaround is sufficient for my use case.

but that said, any chance we can update the readme so let the users know there is a gap between jsonata4java and jsonata? thanks!

wnm3 commented 1 year ago

I've added below to the readme. Please close if this is acceptable (and #267 as well).

image
cuichenli commented 1 year ago

thanks!