Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dart2JS: How to avoid interceptors for JS interop? #35142

Closed
matanlurey opened this issue Nov 13, 2018 · 5 comments
Closed

Dart2JS: How to avoid interceptors for JS interop? #35142

matanlurey opened this issue Nov 13, 2018 · 5 comments

Comments

@matanlurey
Copy link
Contributor

I have code that ~mostly looks like this:

@JS()
library js_interop;

import 'package:js/js.dart';

@JS('self')
external MyGlobals get myGlobals;

@JS()
@anonymous
abstract class MyGlobals {
  external List<String> get names;
  set names(List<String> names);
}

void main() {
  var names = myGlobals.names;
  if (names == null) {
    names = myGlobals.names = [];
  }
}

This fails, mostly mysteriously, with a NoSuchMethodError. While debugging the Dart2JS, I realized that this is going through an Interceptor. The code that is emitted looks something like this:

J.get$names$x = function(receiver) {
  return J.getInterceptor$x(receiver).get$names(receiver);
}

...

JavaScriptObject: {
  get$names: function(obj) {
    return obj.names;
  }
}

...

main: function() {
  var names;
  names = J.get$names$x(self.self);
}

Questions:

  1. In my head, this would work perfectly fine if instead Dart2JS just emitted:
main: function() {
  var names;
  names = self.names;
}

... but I can't tell why it doesn't try to do that. Any pointers? I can point to my internal work.

  1. [Low] Is there a way to avoid reading self.self in this case?
@rakudrama
Copy link
Member

There is a lot here than needs to be fixed via #35084.
Your experience will be helpful to that effort. /cc @jmesserly

As things currently stand, js-interop on dart2js has some issues when the object is also a 'native' type from dart:html etc. Any dynamic (interceptor) lookup will find the dart:html definition.
We need the interceptor lookup because some js libraries return DOM objects, and those objects are expected to have the Dart-only methods defined in dart:html. Originally we didn't have the interceptor lookup and users could not use these libraries from Dart.
(One avenue to explore for improving this 'two worlds' problem is to make 'native' types extend JavaScriptObject, but without considering all the issue of #35084 that would just be a hack. The final solution will make better use of static types and might introduce restrictions to make that possible.)

Since self is a Window, it clashes with the Window type from dart:html.
Can you avoid trying to define the top level scope, and use a getter/setter for each top-level variable?
When you read the top-level variable, assign it to a local of the correct type.
This gives a useful static type to the otherwise essentially dynamic js object type.
For example defining MyGlobals g = myGlobals; and using g will improve the code a little, at least reusing the interceptor.

You would get self.names with a top level getter with the name 'names' (or @js name if you wanted a different Dart name).

A third problem you will have is that in DDC (and dart2js without command line arguments suppressing checks) List<String> is not the right type - since the Array comes from JavaScript, it is List.

@matanlurey
Copy link
Contributor Author

@rakudrama:

Can you avoid trying to define the top level scope, and use a getter/setter for each top-level variable?

Yeah. I could create a set of top-level setters and getters. I'll try that!

For example defining MyGlobals g = myGlobals

Do I need to write specifically that? Does final g = myGlobals do the same thing w/ inference?

A third problem you will have is that ... List<String> is not the right type

Ah. I was trying to avoid returning List<dynamic>, from your other request that we try and type the returns. If it is List<dynamic>, won't Dart2JS consider all native types live again?

@matanlurey
Copy link
Contributor Author

Ping @rakudrama 🏓

@rakudrama
Copy link
Member

The current native analysis ignores type parameters, so <dynamic> should not pull in any new types.

@matanlurey
Copy link
Contributor Author

Thanks! That's enough information for me! Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants