I am trying to create a wrapper for lunr.js (http://lunrjs.com/) in Dart, however, I can find no documentation on how to use this with the Dart js interop.
This is the object I am trying to create:
var index = lunr(function () {
this.field('title', {boost: 10})
this.field('body')
this.ref('id')
})
Currently this is all that I have.
JsObject index = new JsObject(context['lunr'], [()
{
}]);
How am I able to access this from an anonymous function?
Also where do I put the actual lunr.js? I am simply making a wrapper for it so I don't see any reason to have it in a HTML file unless necessary.
EDIT:
I have also tried:
Create a function to allow for using this keyword. (still not sure if this syntax is correct)
_f = new JsFunction.withThis( (t) {
t.callMethod('field', ['title', {boost: 10}])
t.callMethod('field', ['body'])
t.callMethod('ref', ['id'])
});
Then create a JsObject using that function:
JsObject index = new JsObject(context['lunr'], [_f]);
This will give me this error:
Exception: Unhandled exception:
Closure call with mismatched arguments: function 'call'
NoSuchMethodError: incorrect number of arguments passed to method named 'call'
Receiver: Closure: (dynamic) => dynamic
Tried calling: call(Instance of 'JsObject', Instance of 'JsObject')
Found: call(t)
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
Next I tried this:
JsObject index =new JsObject.fromBrowserObject(context['lunr']);
That gives me a different error: Exception: Illegal argument(s): object cannot be a num, string, bool, or null
This may be because I do not have a way to call the _f function when creating the JsObject that way.
You have to use :
context.callMethod('lunr', [_f]);
new JsObject(context['lunr'], [_f]); is the same as new lunr(f) in JS.
I think if you just use it in the function it will be closurized with the function. Otherwise you can try using an emulated function where you pass the this when you instantiate an instance of the emulated function.
class SomeFunction implements Function {
ThisType thisVal;
SomeFunction(this.thisVal);
call(args) {
thisVal.field(...);
}
}
I don't know dart at all, but perhaps you can sidestep the issue of trying to use this entirely. The function you pass to the lunr function has the created index yielded as the first param as well as being the context of the function.
var index = lunr(function (idx) {
idx.field('title', { boost: 10 })
idx.field('body')
idx.ref('id')
})
The above uses the yielded index object rather than relying on the context being set as the index, so you don't need to use this.
Related
I'm using Dart 2.18.0 now. Here's what the docs say about
the entry of Isolate.spawn.
The function must be a top-level function or a static method that can be called with a single argument, that is, a compile-time constant function value which accepts at least one positional parameter and has at most one required positional parameter. The function may accept any number of optional parameters, as long as it can be called with just a single argument. The function must not be the value of a function expression or an instance method tear-off.
Here's the code I write,
import 'dart:io';
import 'dart:isolate';
void main(List<String> args) {
Isolate.spawn((message) {
print("$message ${Isolate.current.debugName}");
}, "Hello world!", debugName: "block");
final p = Person();
Isolate.spawn(p.saySomething, "Nice to meet you!",
debugName: "Object method");
Isolate.spawn(
p.saySomething2(), "A function from the value of a function expression!",
debugName: "Function Expression");
sleep(Duration(seconds: 1));
}
class Person {
void saySomething(String something) {
print("$something ${Isolate.current.debugName}");
}
void Function(String message) saySomething2() {
return saySomething;
}
}
See, I pass a block and a method of a instance to each Isolate.spawn. The code runs well and it prints the following logs.
Hello world! block
Nice to meet you! Object method
A function from the value of a function expression! Function Expression
But how? Block is neither a top level function nor a static function. The function from a value of a function expression and the method of an instance can also be passed as Isolate entry.
Do I get it wrong? Or these features has been supported, the doc has not updated yet?
I think the problem here is that you're passing a function as a parameter, when
Isolate.spawn
expects a function expression.
The docs say:
The function must be a top-level function or a static method that can be called with a single argument, that is, a compile-time constant function value which accepts at least one positional parameter and has at most one required positional parameter. The function may accept any number of optional parameters, as long as it can be called with just a single argument. The function must not be the value of a function expression or an instance method tear-off.
You can see an example of a function expression in the docs here:
int foo(int a, int b) => a + b;
Your
saySomething2
Function returns a function expression, so you can use that directly:
Isolate.spawn(p.saySomething2(), "A function from the value of a function expression!", debugName: "Function Expression");
Consider the following minimal example:
class Element<T> {}
final elements = [
Element<String>(),
Element<int>(),
];
Element<T> transformation<T>(Element<T> element) => Element<T>();
void main() {
// prints 'Element<String>', 'Element<int>'
for (final element in elements) {
print(element);
}
// prints 'Element<Object>', 'Element<Object>',
// but I would like to get identical output as above.
for (final element in elements) {
print(transformation(element));
}
}
I can't figure out how to create a transformation of each Element<T> with its respective generic runtime type T, not the static Object type of the elements collection.
I remember having seen some complicated trick with nested closures in the past, but can't seem to find it anymore. How can I make my function capture the runtime type of T, without having to implement the transformation function in the Element class itself?
That's not possible.
The only way to get access to the type variable of an object is if the object gives it to you.
If Element had a method like
R callWith<R>(R Function<T>(Element<T>) action) => action<E>(this);
then you could get access to the E of Element<E> as a type variable.
You can't do that from outside the class.
I know the usage of anonymous function with () {} but what () {}() mean?
I'm using it in a Text widget like this:
new Text(
() {
return "hello";
}(),
),
It works pretty well but why do I need to add () after the anonymous function?
Without the second set of parentheses, you're just declaring an anonymous function, nothing else. So without that second set, you would be passing a function reference to the Text widget.
Now when you add the second set of parentheses you're actually calling the function that you defined.
If you look at it another way it might make it more clear. If you give that anonymous function a name you'll get the same result.
Function test = () {
return "hello";
};
print(test());
is equivalent to
print(() {
return "hello";
}());
Why the next program produce the runtime error message "Error (R3) : Calling Function without definition !: init"
load "guilib.ring"
new qApp() {
new qWidget() {
setWindowTitle("First App!")
resize(400,400)
show()
}
exec()
}
The next code will fix your problem
Load "guilib.ring"
New qApp {
New qWidget() {
setWindowTitle("First App!")
resize(400,400)
show()
}
exec()
}
Using () after the class name means calling the init() method in the class and passing parameters to this method, using () while no init() method in the class will generate a runtime error message.
the class qApp don’t have this method while the other classes have it because they need it to create an object using a function that return a pointer to that object and this pointer will be stored in an attribute called pObject, for more information see ring_qt.ring file which contains the classes.
I'm reasonably proficient with Groovy insofar as my job requires, but not having a background in OOP means that some things still elude me, so apologies if some of the wording is a little off here (feel free to edit if you can make the question clearer).
I'm trying to create an overloaded method where the signature (ideally) differs only in the return type of the single Closure parameter. The Closure contains a method call that returns either an ItemResponse or ListResponse object, both of which could contain an object/objects of any type (which is the type I would like to infer).
The following code is a simplified version of what I'm trying to implement - an error handling method which takes a reference to a service call, safely attempts to resolve it, and returns the item/items from the response as appropriate:
public <T> T testMethod(Closure<ItemResponse<T>> testCall) {
testCall.call().item as T
}
public <T> List<T> testMethod(Closure<ListResponse<T>> testCall) {
testCall.call().items as T
}
Obviously this doesn't work, but is there any alternate approach/workaround that would achieve the desired outcome?
I'm trying to create an overloaded method where the signature
(ideally) differs only in the return type of the single Closure
parameter.
You cannot do that because the return type is not part of the method signature. For example, the following is not valid:
class Demo {
int doit() {}
String doit() {}
}
As mentioned by yourself and #jeffscottbrown, you can't have two methods with the same parameters but different return value. The workaround I can see here is to use a call-back closure. The return value of your testMethod would default to Object and you would provide an "unwrapper" that would the bit after the closure call (extract item or items). Try this out in your GroovyConsole:
class ValueHolder <T> {
T value
}
Closure<List<Integer>> c = {
[1]
}
Closure<ValueHolder<String>> d = {
new ValueHolder(value:'hello world')
}
Closure liu = {List l ->
l.first()
}
Closure vhsu = {ValueHolder vh ->
vh.value
}
// this is the generic method
public <T> Object testMethod(Closure<T> testCall, Closure<T> unwrapper) {
unwrapper(testCall.call()) as T
}
println testMethod(c, liu)
println testMethod(d, vhsu)
It works with both a list or a value holder.