Is it possible to pass command-line arguments to a new isolate from spawnUri() - dart

When starting a new isolate with spawnUri(), is it possible to pass command line args into that new isolate?
eg: Command line:
dart.exe app.dart "Hello World"
In app.dart
#import("dart:isolate");
main() {
var options = new Options();
print(options.arguments); // prints ["Hello World"]
spawnUri("other.dart");
}
In other.dart
main() {
var options = new Options();
print(options.arguments); // prints [] when spawned from app.dart.
// Is it possible to supply
// Options from another isolate?
}
Although I can pass data into other.dart through its SendPort, the specific use I want is to use another dart app that hasn't been created with a recievePort callback (such as pub.dart, or any other command-line app).

As far as I can tell the answer is currently no, and it would be hard to simulate via message passing because the options would not be available in main().
I think there are two good feature requests here. One is to be able to pass options on spawn() so that a script can run the same from the root isolate or a spawned isolate.
The other feature, which could be used to implement the first, is a way to pass messages that are handled by libraries before main() is invoked so that objects that main() depends on can be initialized with data from the spawning isolate.

Your example doesn't call print(options.arguments); in other.dart using the current stable SDK.
However
spanUri("other.dart");
spawns an Uri. So how about spawnUri("other.dart?param=value#orViaHash"); and try if you can find the param/value pair via
print(options.executable);
print(options.script);

Related

Dart testing Command line program

Suppose I have the following program increment.dart,
import 'dart:io';
void main() {
var input = int.parse(stdin.readLineSync());
print(++input);
}
and I want to test it similar to expect() from test package like,
test('Increment', () {
expect(/*call program with input 0*/ , equals(1));
});
Elaborating my use case:
I use this website to practice by solving the puzzles. They do have an online IDE but it doesn't have any debugging tools and the programs use std io. So what I have to do for debugging my code locally is to replace every stdin.readLineSync() with hardcoded test values and then repeat for every test. I'm looking a way to automate this.(Much like how things work on their site)
Following #jamesdlin's suggestion, I looked up info about Processes and found this example and whipped up the following test:
#TestOn('vm')
import 'dart:convert';
import 'dart:io';
import 'package:test/test.dart';
void main() {
test('Increment 0', () async {
final input = 0;
final path = 'increment.dart';
final process = await Process.start('dart', ['$path']);
// Send input to increment.dart's stdin.
process.stdin.writeln(input);
final lineStream =
process.stdout.transform(Utf8Decoder()).transform(LineSplitter());
// Test output of increment.dart
expect(
lineStream,
emitsInOrder([
// Values match individual events.
'${input + 1}',
// By default, more events are allowed after the matcher finishes
// matching. This asserts instead that the stream emits a done event and
// nothing else.
emitsDone
]));
});
}
Trivia:
#TestOn()
Used to specify a Platform Selector.
Process.start()
Used to run commands from the program itself like, ls -l (code: Process.start('ls', ['-l'])). First argument takes the command to be executed and second argument takes the list of arguments to be passed.
Testing stream

How to create three infinity loop inside isolate?

I am learning Dart and working with Isolate. I wrote next code, and expected that it will create three isolate process that will work infinity:
main() {
Isolate.spawn(echo, "Hello");
Isolate.spawn(echo, "Hello2");
Isolate.spawn(echo, "Hello3");
}
void echo(var message)
{
while(true)
{
print(message);
}
}
But I am getting very strange output like (every time different):
$ dart app.dart
Hello
Hello
Hello
Hello
HelloHello2
Hello
Hello3
Hello2
Hello
The VM will terminate the entire program as soon as the main isolate ends. For you, that happens after you have spawned all three isolates. There is nothing keeping the main isolate alive, so the entire program just ends ... eventually, when the isolate is done shutting down. When that is depends on timing, so it can vary quite a lot.
To keep an isolate alive forever, you can create a ReceivePort. Try addig:
var keepalive = ReceivePort();
to your program, then it should keep running forever.
Also, the printing is not just a list of lines containing hello's, they are intermixed.
The three isolates are running concurrently. They all write to the same output (stdout), so the outputs get intermixed. There is no promise that a print call is atomic, and it isn't, so a print call in one isolate can happen in the middle of a print call in another isolate.
What happens here is that print doesn't just print the argument, it also prints a newline afterwards. Those are two different writes to stdout, so it is possible for another isolate to print its message between the "Hello" and the "\n" following it.

How to run multiple instances of a lua script from C

I have the following lua script :
mydata={}
function update(val)
mydata["x"] = val
if (val == 10)
-- Call C-Api(1)
else
--Register callback with C when free or some event happens
register_callback(callme)
end
function callme()
end
Basically I would like to have two instances of this script running in my C program/process with out having to create a new LUA state per script. And I want to call the function update() with val = 10 from the one instance and call the function update() with val = 20 from another instance. From the second instance it registers a callback function and just waits to be called.
Basically the script file is kind of a RULE that i am trying to achieve.
Several events on the system can trigger this rule or script file. I would like to process this rule as per the event that triggered it. There could be multiple events triggering this script to run at the same time. So I need to have multiple instances of this script running differentiated by the kind of event that triggered it.
To Summarize, I want each caller to have separate individual instance of mydata
I would like to achieve something like this. I read some where that we should be able to run multiple instances of a lua script with out having to create a new lua instance by loading a new environment before loading the script
But I am not able to find the exact details.
Could some body help ?
While I'm still not sure what exactly you are trying to achieve, but if you want to have two instances of the same function that keep the data they use private, you just need to create a closure and return an anonymous function that your C code will use.
Something like this should work:
function createenv(callme)
local mydata={}
return function (val) -- return anonymous function
mydata["x"] = val
if (val == 10)
-- Call C-Api(1)
else
--Register callback with C when free or some event happens
register_callback(callme)
end
end
end
Now in one part of your (C or Lua) code you can do:
local update = createenv(function() --[[do whatever]] end)
update(10)
And then in another part you can do:
local update = createenv(function() --[[do something else]] end)
update(20)
And they should have nothing in common between each other. Note that they still shared the same Lua state, but their instances of mydata will be independent of each other.

Dart isolate call or send

I have a couple questions about how isolate works :
1) What is the difference between call and send and when I should use call over send?
2) Just curiosity, is there any way to chain isolate like we chain Future ?
3)
import 'dart:isolate';
echo() {
port.receive((msg, reply) {
print('I received: $msg');
});
}
main() {
var sendPort = spawnFunction(echo);
sendPort.call('Hello from main');
}
It displays : I received: Hello from main
but when I use send, it prints nothing, why?
Use the call() method on SendPort as a simple way to send a message and receive a reply. The call() method returns a Future for the reply. If you don't bother of the reply and simply want to send a message, use send().
Have a look at dart:isolate - Concurrency with Isolates for more informations.
For 3) it's explained in the above link :
In the standalone VM, the main() function runs in the first isolate (also known as the root isolate). When the root isolate terminates, it terminates the whole VM, regardless of whether other isolates are still running. For more information, see the section called “Keeping the root isolate alive”.

How do you run an interactive process in Dart?

The test below attempts to run the less pager command and return once
the user quits. The problem is that it doesn't wait for user input, it
just lists the entire file and exits. Platform: xubuntu 12.04, Dart
Editor build: 13049.
import 'dart:io';
void main() {
shell('less', ['/etc/mime.types'], (exitCode) => exit(exitCode));
}
void shell(String cmd, List<String> opts, void onExit(int exitCode)) {
var p = Process.start(cmd, opts);
p.stdout.pipe(stdout); // Process output to stdout.
stdin.pipe(p.stdin); // stdin to process input.
p.onExit = (exitCode) {
p.close();
onExit(exitCode);
};
}
The following CoffeeScript function (using nodejs I/O) works:
shell = (cmd, opts, callback) ->
process.stdin.pause()
child = spawn cmd, opts, customFds: [0, 1, 2]
child.on 'exit', (code) ->
process.stdin.resume()
callback code
How can I make this work in Dart?
John has a good example about how to look at user input. But doesn't answer your original question. Unfortunately your question doesn't fit with how Dart operates. The two examples you have, the Dart version and CoffeeScript/Node.js version, do two completely different things.
In your CoffeeScript version, the spawn command is actually creating a new process and then passing execution over to that new process. Basically you're program is not interactively communicating with the process, rather your user is interacting with the spawned process.
In Dart it is different, your program is interacting with the spawned process. It is not passing off execution to the new process. Basically what you are doing is piping the input/output to and from the new process to your program itself. Since your program doesn't have a 'window height' from the terminal, it passes all the information at once. What you're doing in dart is almost equivalent to:
less /etc/mime.types | cat
You can use Process.start() to interactively communicate with processes. But it is your program which is interactively communicating with the process, not the user. Thus you can write a dart program which will launch and automatically play 'zork' or 'adventure' for instance, or log into a remote server by looking at the prompts from process's output.
However, at current there is no way to simply pass execution to the spawned process. If you want to communicate the process output to a user, and then also take user input and send it back to a process it involves an additional layer. And even then, not all programs (such as less) behave the same as they do when launched from a shell environment.
Here's a basic structure for reading console input from the user. This example reads lines of text from the user, and exits on 'q':
import 'dart:io';
import 'dart:isolate';
final StringInputStream textStream = new StringInputStream(stdin);
void main() {
textStream.onLine = checkBuffer;
}
void checkBuffer(){
final line = textStream.readLine();
if (line == null) return;
if (line.trim().toLowerCase() == 'q'){
exit(0);
}
print('You wrote "$line". Now write something else!');
}

Resources