Send multiple arguments to the compute function in Flutter

Viewed 10150

I was trying to use the compute function in Flutter.

void _blockPressHandler(int row, int col) async {
//    Called when user clicks any block on the sudoku board . row and col are the corresponding row and col values ;
    setState(() {
      widget.selCol = col;
      }
    });

    bool boardSolvable;
    boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku , widget.board , widget.size) ;

  }

isBoardInSudoku is a static method of class SudokuAlgorithm. Its present in another file. Writing the above code , tells me that

error: The argument type '(List<List<int>>, int) → bool' can't be assigned to the parameter type '(List<List<int>>) → bool'. (argument_type_not_assignable at [just_sudoku] lib/sudoku/SudokuPage.dart:161)

How do i fix this? Can it be done without bringing the SudokuAlgorithm class's methods out of its file ? How to send multiple arguments to the compute function ?

static bool isBoardInSudoku(List<List<int>>board , int size ){ } is my isBoardInSudoku function.

5 Answers

Just put the arguments in a Map and pass that instead.

There is no way to pass more than one argument to compute because it is a convenience function to start isolates which also don't allow anything but a single argument.

Use a map. Here is an example:

Map map = Map();
map['val1'] = val1;
map['val2'] = val2;
Future future1 = compute(longOp, map);


Future<double> longOp(map) async {
  var val1 = map['val1'];
  var val2 = map['val2'];
   ...
}

In OOP and in general, it is more elegant to create a class for that with fields you need, that gives you more flexibility and less hassle with hardcoded strings or constants for key names.

For example:

boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku , widget.board , widget.size) ;

replace with

class BoardSize{
  final int board;
  final int size;
  BoardSize(this.board, this.size);
}

...

boardSolvable = await compute(SudokuAlgorithm.isBoardInSudoku, BoardSize(widget.board, widget.size)) ;

Use a Tuple

Here is some example code from my app:

  @override
  Future logChange(
      String recordId, AttributeValue newValue, DateTime dateTime) async {
    await compute(
        logChangeNoCompute, Tuple2<String, AttributeValue>(recordId, newValue));
  }

  Future<void> logChangeNoCompute(Tuple2<String, AttributeValue> tuple) async {
    _recordsById[tuple.item1]!.setAttributeValue(tuple.item2);
    await storage.setItem(AssetsFileName, toJson());
  }

You can have a function whose only argument is a Map so that you can pass multiple parameters by passing a Map with properties and values. However, the problem that I'm encountering now is that I cannot pass functions. If the value of a Map's property is a function I get an error when I run the compute function.

This example works(keep in mind that I've imported libraries and that's the reason why some functions and classes definitions aren't in this example)

Future<List<int>> getPotentialKeys({
  @required int p,
  @required int q,
})async{
  return await compute(allKeys,{
    "p" : p,
    "q" : q,
  });
}

List<int> allKeys(Map<String,dynamic> parameters){
  AdvancedCipherGen key = AdvancedCipherGen();
  List<int> possibleE = key.step1(p: parameters["p"], q: parameters["q"]);
  return possibleE;
}

This does not work(same thing with a function as the value of a property thows an error)

Future<List<int>> getPotentialKeys({
  @required int p,
  @required int q,
  @required Function(AdvancedCipherGen key) updateKey,
})async{
  return await compute(allKeys,{
    "p" : p,
    "q" : q,
    "updateKey" : updateKey,
  });
}

List<int> allKeys(Map<String,dynamic> parameters){
  AdvancedCipherGen key = AdvancedCipherGen();
  List<int> possibleE = key.step1(p: parameters["p"], q: parameters["q"]);
  //TODO: Update the key value through callback
  parameters["updateKey"](key);
  return possibleE;
}
Related