Is DartDocs about the entry of `Isolate.spawn` wrong or something? - dart

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");

Related

class parameter or class identifier query

I am new in Dart and works on an app that has a class look like this:
abstract class BaseUseCase <In,Out> {}
My question is then, what is In and Out?
In and Out are type arguments. They are used to allow the code in the class to use objects of an unknown type while remaining consistent and type-safe.
For example, say you wanted to have a method in a class that would take a list of any type, perform a string conversion operation on every element, and then return a strongly typed map of results:
class Stringifier<T> {
Map<T, String> stringify(List<T> input) =>
{for (final entry in input) entry: input.toString()};
}
void main() {
Stringifier<int>().stringify([1, 2, 3]);
// Result: <int, String>{1: '1', 2: '2', 3: '3'}
}
Note that the return type and input argument type use the generic T type. This ensures that only a list of the given type can be passed in, and that the resultant map will have the correct key type.
Type arguments can be used in other declarations as well, such as function declarations - indeed, the example above can be simplified, and declared outside a class:
Map<T, String> stringify(List<T> input) { /* ... */ }
More information on generics can be found in the Dart Language Tour, as well as in the "Generics" section of the Dart 2 language specification.

Dart - The argument type 'String' can't be assigned to the parameter type 'String'

My code is pretty simple:
typedef GenericCallback = void Function<T>(T);
void main() {
GenericCallback callback = <String>(String message) => printMessage(message);
}
void printMessage([String errorMessageReason]) {
print(errorMessageReason ?? '');
}
And DartPad gives me this error at the word message in printMessage(message):
Error: The argument type 'String/*1*/' can't be assigned to the parameter type 'String/*2*/'.
- 'String/*1*/' is from 'unknown'.
- 'String/*2*/' is from 'dart:core'.
It looks like Dart is getting the reference from one String and not the other, how's this even possible?
Since you've done typedef GenericCallback = void Function<T>(T) you need to provide a generic method which matches the signature as a callback. The tricky part here is, you are doing that but not in the way you think.
In this line it looks like you're trying to specify the type for the closure you've created:
GenericCallback callback = <String>(String message) => printMessage(message);
However, Dart's rules for naming generic type parameters are strange in that you can use the names of existing types as the name of the type parameter. In other words, the following lines are all functionally identical and will provide a similar error:
GenericCallback callback = <String>(String message) => printMessage(message);
GenericCallback callback = <T>(T message) => printMessage(message);
GenericCallback callback = <int>(int message) => printMessage(message);
These generic closures are all completely valid and even built-in types like int and String will be treated as the names for type parameters in the scope of the closure.
In order to fix your error, you'll want to change the type parameter String to have a different name that doesn't collide with a core type, and do one of the following:
Update your invocation of printMessage to cast message to a String, although this will fail if T isn't of type String when the closure is called.
GenericCallback callback = <T>(T message) => printMessage(message as String);
Update your typedef to expect a String parameter
typedef GenericCallback = void Function<T extends String>(T);
GenericCallback callback = <T extends String>(T message) => printMessage(message);
This is an easy mistake to make if you've come from a language which allows for template/generic specialization like C++. Keep in mind that, at least currently, you can't specialize a generic method or object and the generic type isn't assigned until the method is actually called or object is created.

Is it possible to specify function with optional parameter as function argument in Dart2?

I am using Dart2
What I want to do is to force developer to use callback that accepts no or at most 1 argument.
For example, having following method:
void doYourJob(void onComplete([result])){ //this is what I have tried, buts its wrong - requires ([arg])=> callback
.... do your job
onComplete(result);
}
I would like to be able to use that method in two ways eg:
doYourJob(()=>doStuff);
and
doYourJob((result)=>doMoreStuffWithResult(result));
Is it possible to do something like this?
No. What you are trying to do is not possible.
You want to have a function type which accepts functions taking either zero or one argument. That is, you want to be able to pass a unary function and a nullary function.
That is, a function type which is a supertype of both void Function() and void Function(Object).
That is not the same as a function type with an optional parameter. Such a function type requires that all arguments must be callable both with zero and one argument. You cannot pass a pure unary function to that, because that function cannot be called with zero arguments.
There is no function type which is a supertype of both void Function() and void Function(Object). The nearest supertype is Function, which accepts any function, not just unary and nullary ones. You can use that, but you lose the type checking.
You can do this by creating a typedef
typedef Callback = Null Function([String data]);
void doYourJob(Callback onComplete) {
onComplete('Data');
onComplete();
}
OR
You can pass the Function directly
void doYourJob(Null Function([String data]) onComplete) {
onComplete('Data');
onComplete();
}
You can call this method like this
void main() {
doYourJob(([String data]) {
print('DATA: $data');
});
}

Google Dart requestAnimationFrame doesnt accept callback

import 'dart:html';
main() {
new test();
}
class test {
test() {
print(x);
}
void x() {
window.requestAnimationFrame(x);
}
}
I could use animationFrame but I want more control so I try to use requestAnimationFrame (without futures). So I call the method from my window object and pass in the callback only to get the following error message:
The argument type '() → void' cannot be assigned to the parameter type 'FrameRequestCallback(num) → void'.
https://dartpad.dartlang.org/fb763a4a770b5cdd896982e10ccf4118
According to dart my x variable is a closure of instance test, great. It cant be void then.
The documentation clearly states the function accepts a callback of type FrameRequestCallback (the method I assume). The function then returns an integer / num. Why doesnt my test project work?
https://api.dartlang.org/stable/1.21.1/dart-html/FrameRequestCallback.html shows that a param of type num is expected.
This should work then
void x(num value) {
window.requestAnimationFrame(x);
}

Overloading a method in Groovy using Closure arguments with different return types

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.

Resources