Skip to content

Interfaces marked as @JsFunction have property length set to 0Β #9675

Open

Description

@vasvir

The issue is in current git of gwt and it is not browser related. The problematic code is at https://github.com/gwtproject/gwt/blob/master/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Runtime.java#L162

Looks like that some javascript libraries are checking on the argument length of the callbacks that are passed to them.

So for example D3 bisector can take a function with one or two arguments. If it is one then it is an accessor if it is two then it is a comparator.

Steps to reproduce

`

@JsFunction
public static interface SomeFunction {
    public double call(double x);
}

@Override
public void onModuleLoad() {
    final SomeFunction y = new SomeFunction() {
        @Override
        public double call(double x) {
            return 2 * x;
        }
    };
    DomGlobal.console.log(y);
    return;    
}

`
Note in the attached image that the reported length of the generated function is 0 instead of 1.

image

Known workarounds

There is no known workaround.

Links to further discussions

This issue has been reported at https://groups.google.com/forum/#!topic/Google-Web-Toolkit/-qaL4dzZm_E

Activity

  1. added a commit that references this issue on Dec 2, 2019
  2. vasvir commented on Jan 14, 2020

    @vasvir
    Author

    There is a fiddle with a bit more experimentation and benchmarks at https://jsfiddle.net/vasvir/forwtzqd/

    The current patch implements a hardwired switch statement with 10 branches. So an argument count of up to10 is supported with this implementation. If the function has more than 10 arguments then the argument count is set to 10.

    In the original implementation the argument count of the functions was set to 0 disregarding the actual input arguments. The patch does not prevent to create lambda with > 10 arguments. It just corrects the argument count (function.length) in the cases <= 10.

    If the need arises in the future to support argument counts > 10 the required extension of the function is trivial and straightforward.

  3. rluble commented on Jan 14, 2020

    @rluble
    Contributor

    For browser with es6 support I believe that makeLambdaFunction could be written as

    function makeLambdaFunction(samMethod, ctor, ctorArguments) {
      var lambda = function(...args) {
        return samMethod.apply(lambda, args);
      }
      ctor.apply(lambda, ctorArguments);
      return lambda;
    }

    but that would not fix the issue, since now probably the length would be always 1. GWT could also generate the makeLambdaFunction code for each lambda with the declared number of parameters but that would introduce an unnecessary codesize cost.

    In any case deciding what to do based on the declared argument count is a poor practice IMHO. The simplest work around would be to have wrapper functions to be used with the particular libraries, e.g.

    function asComparator(fn) {
      return function(a, b) { return fn(a,b); };
    }
    
    function asAccessor(fn) {
      return function(a) { return fn(a); };
    }
  4. vasvir commented on Jan 15, 2020

    @vasvir
    Author

    The workaround you suggest is valid and this what I have done in my D3 bindings.

    When I said there are no workarounds I was talking about setting correctly the function.length in the generated lambda.

    Furthermore I agree that I don't like the API that accepts two different callbacks (accessor and comparator) in one method that checks arguments count.

    But...

    • The unfolding of this bug/issue took me some hours. I am certain that other people trying to write jsinterop will be bitten also in the future.
    • Splitting the interface with wrappers is natural for Java but unnatural for Js. It involves creating a @JsOverlay method that has 2 different signatures in order to invoke the wrappers. Not sure if it can be done without JSNI. I think that introduces friction between Js libraries and Java jsinterop bindings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions