I would like to use JS interop to expose a set of functions/objects coded in dart.
I know how to use js-interop to share variables with JS scripts. But I have a requirement : I can't edit dart classes as they are coming from an external library without JS dependency.
And while I know it's possible to do something like :
#anonymous
#JS()
class Config {
external bool get value;
external factory Config({bool value});
factory Config.fromExternalLib(ExternalConfig config) {
return new Config(value: config.value);
}
}
I'd like to avoid that, as it requires to duplicate every classes.
Is there any way to convert any dart object to JS object without modifying or forking the class ?
Related
I have a class that extends another. The parent class is not intended to be used directly by the API rather it implements basic methods that are helpers for child classes.
When I use the child class in a program I can see all method from said class but also the one from the parent class that are not intended to be called directly, they exist to be called by the methods of the child class.
I tried to make parents method private. This would work I believe as long as parent and child are declared in the same library. But I have an issue with the "library" notion. I understand part/part of are somewhat depreciated, and I want the parent class to be in a specific file. I can't figure a way to do it with import/export.
Is there a way to either hide a public method from the parent class from all child classes usage or to make a private method from the parent class callable from all child classes ?
Best regards ;
Exemple:
myLib.dart
export mainClass.dart;
mainClass.dar
import baseClass.dart;
class MainClass extends BaseClass {
publicFunc() => ... //Can't call _hiddenFunc, can call wantToHideFunc()
}
In a second file (for code reusability purposes)
class MainClass extends BaseClass {
_hiddenFunc() => ...
wantToHideFunc() => ...
}
Using myLib public API
import myLib.dart
main() {
class = Class();
class.publicFunc(); //Intended
class.wantToHideFunc() //Wants to avoid...
}
Dart does not have protected access like Java or C#.
You can't hide a public member, you can't access a private member from a different library, and there is no third option.
It sounds like you want members of the superclass which can be invoked only from subclasses, not from outside of the object. That's what's called protected in, e.g., Java, and Dart does not have anything similar to that.
The only level of privacy in Dart is library-private, which is chosen by starting the name with a _.
The reason that Dart has this design is that it was originally a very dynamic language. You can preform "dynamic invocations" on a value with static type dynamic, say dynVal.foo(42) and it will call the method of that name.
To make a name unreachable, it needed to be safe from dynamic invocation as well. Because of that, Dart privacy does not care where the code doing the invocation is, it only cares whether you know the name - and library private names are considered different names depending on which library they're from.
Using part is not discouraged for situations where it actually serves a purpose. If you can put the part into a library of its own, that's better because it allows it to have its own privacy and imports, but if you need the classes to share privacy, using part files to split up a large file is perfectly reasonable. It's a tool, there is nothing wrong with using it when it's the right tool for the job. A library is often a better tool for modularity, but not always.
Now, there is a hack you can use:
// Declare the base and provide extensions for "protected" members:
abstract class Base {
int get _someHiddenStuff => 42;
int get somePublicStuff => 37;
}
extension ProtectedBase on Base {
int get someHiddenStuff => _someHiddenStuff;
}
Then import that in another library and do:
import "base.dart";
export "base.dart" hide ProtectedBase;
class SubClass extends Base {
int doSomething => someHiddenStuff + somePublicStuff;
}
Then anyone importing "subclass.dart" will also get a version of Base, but they won't get the ProtectedBase extensions. Hiding the extensions from your package's public API will allow yourself to use it, but prevent your package's users from seeing the helper extensions.
(This is likely highly over-engineered, but it's an option. It's the evolution of the hack of having static/top-level helper functions that you don't export.)
Set the case there are multiple libraries of a package which need access to a commonly used class which is in its own library. This class gets exported and contains private fields which should only be accessible internally by libraries of the package. Because the part of directive is discouraged I am avoiding it. So this is the challenge: How can I access private fields of a public class from another library of the same package without using part of?
This is what a came up with:
class PublicClass {
Object _shouldNotBePublic;
}
class InternalClass extends PublicClass {
Object get publicInternally => _shouldNotBePublic;
}
And it partially solves the problem.
But now there is an exported function
void someFunction(PublicClass param) {
param._shouldNotBePublic;
}
which takes an argument of PublicClass and it needs to access the private _shouldNotBePublic field. That is exactly what C++ friend does. Are there any good solutions for Dart that don't involve part of?
Edit: The workaround I use for the time being is a simple not exported function in the same library like PublicClass:
Object getShouldNotBePublic(PublicClass obj) {
return obj._shouldNotBePublic
}
In F#, can I omit the class name when calling a static method?
Example:
In C#, I can do something like:
using static Bizmonger.Patterns.MessageBus;
...
Publish("SOME_MESSAGE");
instead of:
MessageBus.Publish("SOME_MESSAGE");
Can I do something like this in F#?
In F#, you can use open on namespaces (just like using in C#) or on modules (which is useful when the API you are calling has been written in F#), but not on static classes (which is what you'd need when calling C# libraries).
One thing that you can do though to make the code a bit shorter is to define a type alias:
type M = Bizmonger.Patterns.MessageBus;
// Now you can write just
M.Publish("SOME_MESSAGE")
// Rather than writing the full
MessageBus.Publish("SOME_MESSAGE");
There is a feature request on the F# UserVoice to allow using open on static classes (just like in C#) and so if you'd like this to happen, please upvote and comment there.
I also learned that I could implement a function to serve as a wrapper for clients to call instead.
Create a wrapper function
module Messages
open Bizmonger.Patterns
let Publish (message:string, payload:_) =
MessageBus.Publish(message, payload)
Client
Then a client can now invoke a function without specifying a class name.
open Messages
...
Publish("SOME_MESSAGE", null);
While trying to port old code running Rhino engine to Nashorn in Java 8, I got the trouble, static properties/methods cannot be accessed from running js script. If I use Rhino, it runs perfectly. I don't know what happens with the implementation of the new Nashorn engine.
import javax.script.*;
public class StaticVars {
public static String myname = "John\n";
public static void main(String[] args) {
try{
ScriptEngine engine;
ScriptEngineManager manager = new ScriptEngineManager();
engine=System.getProperty("java.version").startsWith("1.8")?
manager.getEngineByName("Nashorn") : //j1.8_u51
manager.getEngineByName("JavaScript"); //j1.7
engine.put("staticvars", new StaticVars());
engine.eval("print(staticvars.myname);");
//print "John" if ran with java 7
//print "undefined" if ran with java 8
} catch(Exception e){e.printStackTrace();}
}
}
In Nashorn, you can't access class static members through class instances. There are multiple ways to get at statics. You can obtain a type object that acts as both a constructor and as a static namespace, much like a type name acts in Java:
var StaticVars = Java.type("StaticVars"); // use your full package name if you have it
print(StaticVars.myname);
Or, pass in a java.lang.Class object and use the .static pseudo-property to access the statics:
engine.put("StaticVarsClass", StaticVars.class);
followed by:
var StaticVars = StaticVarsClass.static;
print(StaticVars.myname);
in the script. In general, .static is the inverse operation to .class:
var BitSet = Java.type("java.util.BitSet");
var bitSetClass = BitSet.class; // produces a java.lang.Class object, just like in Java
print(BitSet === bitSetClass.static); // prints true
var bitSet = new BitSet(); // type object creates a new bitset when used as a constructor
var thisWontWork = new bitSetClass(); // java.lang.Class can't be used as a constructor.
As you can see, we distinguish three concepts:
the runtime class objects, which are instances of java.lang.Class. They aren't special, and you only can use the Class API on them (.getSuperclass(), .getName(), etc.)
instances of classes themselves (normal objects that you can access instance members on)
type objects, which are both namespaces for static members of classes they represent, as well as constructors. The closest equivalent in Java to them is the name of the class as used in source code; in JavaScript they are actual objects.
This actually produces least ambiguity, as everything is in its place, and maps most closely to Java platform idioms.
This is not the way js should work. I think this is a design bug in Nashorn. Assume you have a mixed util passing vars from some java runtime system to the js script. This object contains one static method fmtNumber(someString) and one object method jutil.getFormVar(someString). The users don't need to know that Java is serving this platform. You simply tell them jutil is a "system hook" belonging to the framework foo. As a user of this framework I don't care about if its static or not. I am a js developer, i don't know about static or not. I want to script something real quick. This is how the code in rhino looks like.
var x = jutil.getFormVar("x");
print(jutil.fmtNumber(x));
Now in nashorn I have to distinguish between them. Even worse I even have to educate my users to distinguish between them and teach them java terms, which they might not know because this is what an abstraction layer is all about: a self containing system without the need to know the underlying mechanisms. This distinction is way to much cognitive overload and you did not think about other usecases than java developers scripting for them self which they probably wont to because the already know a good language called Java. You are thinking form your implementation as a Java developer when instead you should think how you could use the power of the Java Plattform in the background, hiding all the nasty details from JS developers. What would a webdeveloper say if he needs to distinguish between the static C++ implementation in the browser?
I have a Dart class (foo.dart):
class Foo {
void talk() {
print('Hello');
}
}
After compiling foo.dart to JavaScript, I'd like to be able to use Foo like this:
var foo = new Foo(); // from foo.dart.js
foo.talk() // prints "Hello"
My questions:
Is this currently possible?
If so, how?
If not, what plans, if any, are in place to make it possible?
The dart:js library documentation states:
This library does not yet make Dart objects usable from JavaScript, their methods and proeprties [sic] are not accessible, though it does allow Dart functions to be passed into and called from JavaScript.
That word "yet" offers some hope, but I've found very little on this topic anywhere else.
Edit:
I do realize it's possible to call Dart functions from JavaScript using dart2js. However, what I'm trying to do is somewhat different. I'd like to be able to access all of the functionality of a Dart class from JavaScript.
Due to tree-shaking and minification this is normally not possible. If you have a Dart application (with a main() then you can make a Dart function available to be called from JavaScript (see How to call a Dart function from Javascript? for an example).
As far as I know there are plans to support your requirement but I have no idea about progress or when such a feature might be available.
This is the related project https://github.com/dart-lang/js-interop