| Index: runtime/bin/file_impl.dart | 
| diff --git a/runtime/bin/file_impl.dart b/runtime/bin/file_impl.dart | 
| index fc966cf941b9c4ccf82c78e667093e2792daf50c..10a5cfc9b393f835ab03825f7a5dcabc3e2c79ce 100644 | 
| --- a/runtime/bin/file_impl.dart | 
| +++ b/runtime/bin/file_impl.dart | 
| @@ -7,9 +7,12 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { | 
| var file = new File(name); | 
| _data = []; | 
| _position = 0; | 
| -    file.onError = _reportError; | 
| -    file.open(FileMode.READ, (openedFile) { | 
| -      _readDataFromFile(openedFile); | 
| +    var chained = file.open(FileMode.READ).chain((openedFile) { | 
| +      return _readDataFromFile(openedFile); | 
| +    }); | 
| +    chained.handleException((e) { | 
| +      _reportError(e); | 
| +      return true; | 
| }); | 
| } | 
|  | 
| @@ -18,31 +21,35 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { | 
| var file = _File._openStdioSync(fd); | 
| _data = []; | 
| _position = 0; | 
| -    _readDataFromFile(file); | 
| +    _readDataFromFile(file).handleException((e) { | 
| +      _reportError(e); | 
| +      return true; | 
| +    }); | 
| } | 
|  | 
| -  void _readDataFromFile(RandomAccessFile openedFile) { | 
| -    openedFile.onError = _reportError; | 
| -    openedFile.length((length) { | 
| +  Future<RandomAccessFile> _closeAfterRead(RandomAccessFile openedFile) { | 
| +    return openedFile.close().transform((ignore) { | 
| +      _streamMarkedClosed = true; | 
| +      _checkScheduleCallbacks(); | 
| +      return openedFile; | 
| +    }); | 
| +  } | 
| + | 
| +  Future<RandomAccessFile> _readDataFromFile(RandomAccessFile openedFile) { | 
| +    return openedFile.length().chain((length) { | 
| var contents = new Uint8List(length); | 
| if (length != 0) { | 
| -        openedFile.readList(contents, 0, length, (read) { | 
| +        return openedFile.readList(contents, 0, length).chain((read) { | 
| if (read != length) { | 
| -            _reportError(new FileIOException( | 
| -                'Failed reading file contents in FileInputStream')); | 
| +            throw new FileIOException( | 
| +                'Failed reading file contents in FileInputStream'); | 
| } else { | 
| _data = contents; | 
| } | 
| -          openedFile.close(() { | 
| -            _streamMarkedClosed = true; | 
| -            _checkScheduleCallbacks(); | 
| -          }); | 
| +          return _closeAfterRead(openedFile); | 
| }); | 
| } else { | 
| -        openedFile.close(() { | 
| -          _streamMarkedClosed = true; | 
| -          _checkScheduleCallbacks(); | 
| -        }); | 
| +        return _closeAfterRead(openedFile); | 
| } | 
| }); | 
| } | 
| @@ -85,28 +92,20 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { | 
| _FileOutputStream(String name, FileMode mode) { | 
| _pendingOperations = new List<List<int>>(); | 
| var f = new File(name); | 
| -    f.open(mode, (openedFile) { | 
| +    var openFuture = f.open(mode); | 
| +    openFuture.then((openedFile) { | 
| _file = openedFile; | 
| -      _setupFileHandlers(); | 
| _processPendingOperations(); | 
| }); | 
| -    f.onError = _reportError; | 
| +    openFuture.handleException((e) { | 
| +      _reportError(e); | 
| +      return true; | 
| +    }); | 
| } | 
|  | 
| _FileOutputStream.fromStdio(int fd) { | 
| assert(1 <= fd && fd <= 2); | 
| _file = _File._openStdioSync(fd); | 
| -    _setupFileHandlers(); | 
| -  } | 
| - | 
| - | 
| -  void _setupFileHandlers() { | 
| -    _file.onError = _reportError; | 
| -    _file.onNoPendingWrites = () { | 
| -      if (!_streamMarkedClosed && _onNoPendingWrites != null) { | 
| -        _onNoPendingWrites(); | 
| -      } | 
| -    }; | 
| } | 
|  | 
| bool write(List<int> buffer, [bool copyBuffer = false]) { | 
| @@ -140,7 +139,7 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { | 
| if (_file == null) { | 
| _pendingOperations.add(null); | 
| } else if (!_streamMarkedClosed) { | 
| -      _file.close(() { | 
| +      _file.close().then((ignore) { | 
| if (_onClosed != null) _onClosed(); | 
| }); | 
| _streamMarkedClosed = true; | 
| @@ -149,6 +148,16 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { | 
|  | 
| void set onNoPendingWrites(void callback()) { | 
| _onNoPendingWrites = callback; | 
| +    if (((_pendingOperations == null) || (_pendingOperations.length == 0)) && | 
| +        (outstandingWrites == 0) && | 
| +        !_streamMarkedClosed && | 
| +        (_onNoPendingWrites != null)) { | 
| +      new Timer(0, (t) { | 
| +        if (_onNoPendingWrites != null) { | 
| +          _onNoPendingWrites(); | 
| +        } | 
| +      }); | 
| +    } | 
| } | 
|  | 
| void set onClosed(void callback()) { | 
| @@ -163,7 +172,21 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { | 
| } | 
|  | 
| void _write(List<int> buffer, int offset, int len) { | 
| -    _file.writeList(buffer, offset, len); | 
| +    outstandingWrites++; | 
| +    var writeListFuture = _file.writeList(buffer, offset, len); | 
| +    writeListFuture.then((ignore) { | 
| +        outstandingWrites--; | 
| +        if ((outstandingWrites == 0) && | 
| +            !_streamMarkedClosed && | 
| +            (_onNoPendingWrites != null)) { | 
| +          _onNoPendingWrites(); | 
| +        } | 
| +    }); | 
| +    writeListFuture.handleException((e) { | 
| +      outstandingWrites--; | 
| +      _reportError(e); | 
| +      return true; | 
| +    }); | 
| } | 
|  | 
| RandomAccessFile _file; | 
| @@ -176,6 +199,9 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { | 
| // the stream is fully closed. | 
| bool _closeCallbackCalled = false; | 
|  | 
| +  // Number of writes that have not yet completed. | 
| +  int outstandingWrites = 0; | 
| + | 
| // List of pending writes that were issued before the underlying | 
| // file was successfully opened. | 
| List<List<int>> _pendingOperations; | 
| @@ -368,43 +394,25 @@ class _FileUtils { | 
|  | 
| // Base class for _File and _RandomAccessFile with shared functions. | 
| class _FileBase { | 
| -  void _reportError(e) { | 
| -    if (_onError != null) { | 
| -      _onError(e); | 
| -    } else { | 
| -      throw e; | 
| -    } | 
| -  } | 
| - | 
| bool _isErrorResponse(response) { | 
| return response is List && response[0] != _FileUtils.kSuccessResponse; | 
| } | 
|  | 
| -  void _handleErrorResponse(response, String message) { | 
| +  Exception _exceptionFromResponse(response, String message) { | 
| assert(_isErrorResponse(response)); | 
| switch (response[_FileUtils.kErrorResponseErrorType]) { | 
| case _FileUtils.kIllegalArgumentResponse: | 
| -        _reportError(new IllegalArgumentException()); | 
| -        break; | 
| +        return new IllegalArgumentException(); | 
| case _FileUtils.kOSErrorResponse: | 
| var err = new OSError(response[_FileUtils.kOSErrorResponseMessage], | 
| response[_FileUtils.kOSErrorResponseErrorCode]); | 
| -        _reportError(new FileIOException(message, err)); | 
| -        break; | 
| +        return new FileIOException(message, err); | 
| case _FileUtils.kFileClosedResponse: | 
| -        _reportError(new FileIOException("File closed")); | 
| -        break; | 
| +        return new FileIOException("File closed"); | 
| default: | 
| -        _reportError(new Exception("Unknown error")); | 
| -        break; | 
| +        return new Exception("Unknown error"); | 
| } | 
| } | 
| - | 
| -  void set onError(void handler(e)) { | 
| -    _onError = handler; | 
| -  } | 
| - | 
| -  Function _onError; | 
| } | 
|  | 
| // Class for encapsulating the native implementation of files. | 
| @@ -412,36 +420,42 @@ class _File extends _FileBase implements File { | 
| // Constructor for file. | 
| _File(String this._name); | 
|  | 
| -  void exists(void callback(bool exists)) { | 
| +  Future<bool> exists() { | 
| _ensureFileService(); | 
| +    Completer<bool> completer = new Completer<bool>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kExistsRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot open file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, "Cannot open file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| bool existsSync() { | 
| return _FileUtils.checkedExists(_name); | 
| } | 
|  | 
| -  void create(void callback()) { | 
| +  Future<File> create() { | 
| _ensureFileService(); | 
| +    Completer<File> completer = new Completer<File>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kCreateRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot create file"); | 
| +        var e = _exceptionFromResponse(response, "Cannot create file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(); | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void createSync() { | 
| @@ -451,36 +465,44 @@ class _File extends _FileBase implements File { | 
| } | 
| } | 
|  | 
| -  void delete(void callback()) { | 
| +  Future<File> delete() { | 
| _ensureFileService(); | 
| +    Completer<File> completer = new Completer<File>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kDeleteRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot delete file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, "Cannot delete file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(); | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void deleteSync() { | 
| _FileUtils.checkedDelete(_name); | 
| } | 
|  | 
| -  void directory(void callback(Directory dir)) { | 
| +  Future<Directory> directory() { | 
| _ensureFileService(); | 
| +    Completer<Directory> completer = new Completer<Directory>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kDirectoryRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot retrieve directory for file"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "Cannot retrieve directory for " | 
| +                                       "file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(new Directory(response)); | 
| +        completer.complete(new Directory(response)); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| Directory directorySync() { | 
| @@ -488,13 +510,16 @@ class _File extends _FileBase implements File { | 
| return new Directory(_FileUtils.directory(_name)); | 
| } | 
|  | 
| -  void open(FileMode mode, void callback(RandomAccessFile file)) { | 
| +  Future<RandomAccessFile> open([FileMode mode = FileMode.READ]) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| if (mode != FileMode.READ && | 
| mode != FileMode.WRITE && | 
| mode != FileMode.APPEND) { | 
| -      _reportError(new IllegalArgumentException()); | 
| -      return; | 
| +      new Timer(0, (t) { | 
| +        completer.completeException(new IllegalArgumentException()); | 
| +      }); | 
| +      return completer.future; | 
| } | 
| List request = new List(3); | 
| request[0] = _FileUtils.kOpenRequest; | 
| @@ -502,26 +527,32 @@ class _File extends _FileBase implements File { | 
| request[2] = mode._mode;  // Direct int value for serialization. | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot open file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, "Cannot open file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(new _RandomAccessFile(response, _name)); | 
| +        completer.complete(new _RandomAccessFile(response, _name)); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| -  void length(void callback(int length)) { | 
| +  Future<int> length() { | 
| _ensureFileService(); | 
| +    Completer<int> completer = new Completer<int>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kLengthFromNameRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, | 
| -                             "Cannot retrieve length of file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "Cannot retrieve length of " | 
| +                                       "file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int lengthSync() { | 
| @@ -553,18 +584,23 @@ class _File extends _FileBase implements File { | 
| return new _RandomAccessFile(id, ""); | 
| } | 
|  | 
| -  void fullPath(void callback(String result)) { | 
| +  Future<String> fullPath() { | 
| _ensureFileService(); | 
| +    Completer<String> completer = new Completer<String>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kFullPathRequest; | 
| request[1] = _name; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "Cannot retrieve full path"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "Cannot retrieve full path" | 
| +                                       " for '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| String fullPathSync() { | 
| @@ -584,18 +620,20 @@ class _File extends _FileBase implements File { | 
| return new _FileOutputStream(_name, mode); | 
| } | 
|  | 
| -  void readAsBytes(void callback(List<int> bytes)) { | 
| +  Future<List<int>> readAsBytes() { | 
| _ensureFileService(); | 
| +    Completer<List<int>> completer = new Completer<List<int>>(); | 
| var chunks = new _BufferList(); | 
| var stream = openInputStream(); | 
| stream.onClosed = () { | 
| -      callback(chunks.readBytes(chunks.length)); | 
| +      completer.complete(chunks.readBytes(chunks.length)); | 
| }; | 
| stream.onData = () { | 
| var chunk = stream.read(); | 
| chunks.add(chunk); | 
| }; | 
| -    stream.onError = (e) => _reportError(e); | 
| +    stream.onError = completer.completeException; | 
| +    return completer.future; | 
| } | 
|  | 
| List<int> readAsBytesSync() { | 
| @@ -610,17 +648,12 @@ class _File extends _FileBase implements File { | 
| return result; | 
| } | 
|  | 
| -  void readAsText(Encoding encoding, void callback(String text)) { | 
| +  Future<String> readAsText([Encoding encoding = Encoding.UTF_8]) { | 
| _ensureFileService(); | 
| var decoder = _StringDecoders.decoder(encoding); | 
| -    readAsBytes((bytes) { | 
| -      try { | 
| -        decoder.write(bytes); | 
| -      } catch (var e) { | 
| -        _reportError(e); | 
| -        return; | 
| -      } | 
| -      callback(decoder.decoded); | 
| +    return readAsBytes().transform((bytes) { | 
| +      decoder.write(bytes); | 
| +      return decoder.decoded; | 
| }); | 
| } | 
|  | 
| @@ -647,17 +680,13 @@ class _File extends _FileBase implements File { | 
| return result; | 
| } | 
|  | 
| -  void readAsLines(Encoding encoding, void callback(List<String> lines)) { | 
| +  Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) { | 
| _ensureFileService(); | 
| +    Completer<List<String>> completer = new Completer<List<String>>(); | 
| var decoder = _StringDecoders.decoder(encoding); | 
| -    readAsBytes((bytes) { | 
| -      try { | 
| -        decoder.write(bytes); | 
| -      } catch (var e) { | 
| -        _reportError(e); | 
| -        return; | 
| -      } | 
| -      callback(_getDecodedLines(decoder)); | 
| +    return readAsBytes().transform((bytes) { | 
| +      decoder.write(bytes); | 
| +      return _getDecodedLines(decoder); | 
| }); | 
| } | 
|  | 
| @@ -676,7 +705,7 @@ class _File extends _FileBase implements File { | 
| } | 
| } | 
|  | 
| -  String _name; | 
| +  final String _name; | 
|  | 
| SendPort _fileService; | 
| } | 
| @@ -685,10 +714,17 @@ class _File extends _FileBase implements File { | 
| class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| _RandomAccessFile(int this._id, String this._name); | 
|  | 
| -  void close(void callback()) { | 
| +  Future<RandomAccessFile> close() { | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| if (_id == 0) { | 
| -      _reportError(new FileIOException("Cannot close file '$_name'")); | 
| -      return; | 
| +      // Complete asynchronously so the user has a chance to setup | 
| +      // handlers without getting exceptions when registering the | 
| +      // then handler. | 
| +      new Timer(0, (t) { | 
| +        completer.completeException( | 
| +            new FileIOException("Cannot close file '$_name'")); | 
| +      }); | 
| +      return completer.future; | 
| } | 
| _ensureFileService(); | 
| List request = new List(2); | 
| @@ -700,11 +736,13 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| _fileService.call(request).then((result) { | 
| if (result != -1) { | 
| _id = result; | 
| -        callback(); | 
| +        completer.complete(this); | 
| } else { | 
| -        _reportError(new FileIOException("Cannot close file '$_name'")); | 
| +        completer.completeException( | 
| +            new FileIOException("Cannot close file '$_name'")); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void closeSync() { | 
| @@ -715,18 +753,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| _id = id; | 
| } | 
|  | 
| -  void readByte(void callback(int byte)) { | 
| +  Future<int> readByte() { | 
| _ensureFileService(); | 
| +    Completer<int> completer = new Completer<int>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kReadByteRequest; | 
| request[1] = _id; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "readByte failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "readByte failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int readByteSync() { | 
| @@ -738,13 +780,18 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void readList(List<int> buffer, int offset, int bytes, | 
| -                void callback(int read)) { | 
| +  Future<int> readList(List<int> buffer, int offset, int bytes) { | 
| _ensureFileService(); | 
| +    Completer<int> completer = new Completer<int>(); | 
| if (buffer is !List || offset is !int || bytes is !int) { | 
| -      _reportError(new FileIOException( | 
| -          "Invalid arguments to readList for file '$_name'")); | 
| -      return; | 
| +      // Complete asynchronously so the user has a chance to setup | 
| +      // handlers without getting exceptions when registering the | 
| +      // then handler. | 
| +      new Timer(0, (t) { | 
| +        completer.completeException(new FileIOException( | 
| +            "Invalid arguments to readList for file '$_name'")); | 
| +      }); | 
| +      return completer.future; | 
| }; | 
| List request = new List(3); | 
| request[0] = _FileUtils.kReadListRequest; | 
| @@ -752,14 +799,17 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| request[2] = bytes; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "readList failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "readList failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| var read = response[1]; | 
| var data = response[2]; | 
| buffer.setRange(offset, read, data); | 
| -        callback(read); | 
| +        completer.complete(read); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int readListSync(List<int> buffer, int offset, int bytes) { | 
| @@ -782,24 +832,33 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void writeByte(int value) { | 
| +  Future<RandomAccessFile> writeByte(int value) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| if (value is !int) { | 
| -      _reportError(new FileIOException( | 
| -          "Invalid argument to writeByte for file '$_name'")); | 
| -      return; | 
| +      // Complete asynchronously so the user has a chance to setup | 
| +      // handlers without getting exceptions when registering the | 
| +      // then handler. | 
| +      new Timer(0, (t) { | 
| +          completer.completeException(new FileIOException( | 
| +              "Invalid argument to writeByte for file '$_name'")); | 
| +      }); | 
| +      return completer.future; | 
| } | 
| List request = new List(3); | 
| request[0] = _FileUtils.kWriteByteRequest; | 
| request[1] = _id; | 
| request[2] = value; | 
| -    _writeEnqueued(); | 
| _fileService.call(request).then((response) { | 
| -      _writeCompleted(); | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "writeByte failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "writeByte failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| +      } else { | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int writeByteSync(int value) { | 
| @@ -816,12 +875,18 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void writeList(List<int> buffer, int offset, int bytes) { | 
| +  Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| if (buffer is !List || offset is !int || bytes is !int) { | 
| -      _reportError(new FileIOException( | 
| +      // Complete asynchronously so the user has a chance to setup | 
| +      // handlers without getting exceptions when registering the | 
| +      // then handler. | 
| +      new Timer(0, (t) { | 
| +          completer.completeException(new FileIOException( | 
| "Invalid arguments to writeList for file '$_name'")); | 
| -      return; | 
| +      }); | 
| +      return completer.future; | 
| } | 
|  | 
| List result = | 
| @@ -835,13 +900,16 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| request[2] = outBuffer; | 
| request[3] = outOffset; | 
| request[4] = bytes; | 
| -    _writeEnqueued(); | 
| _fileService.call(request).then((response) { | 
| -      _writeCompleted(); | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "writeList failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "writeList failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| +      } else { | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int writeListSync(List<int> buffer, int offset, int bytes) { | 
| @@ -863,19 +931,24 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void writeString(String string, [Encoding encoding = Encoding.UTF_8]) { | 
| +  Future<RandomAccessFile> writeString(String string, | 
| +                                       [Encoding encoding = Encoding.UTF_8]) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| List request = new List(3); | 
| request[0] = _FileUtils.kWriteStringRequest; | 
| request[1] = _id; | 
| request[2] = string; | 
| -    _writeEnqueued(); | 
| _fileService.call(request).then((response) { | 
| -      _writeCompleted(); | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "writeString failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "writeString failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| +      } else { | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { | 
| @@ -887,18 +960,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void position(void callback(int position)) { | 
| +  Future<int> position() { | 
| _ensureFileService(); | 
| +    Completer<int> completer = new Completer<int>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kPositionRequest; | 
| request[1] = _id; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "position failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "position failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int positionSync() { | 
| @@ -910,19 +987,23 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void setPosition(int position, void callback()) { | 
| +  Future<RandomAccessFile> setPosition(int position) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| List request = new List(3); | 
| request[0] = _FileUtils.kSetPositionRequest; | 
| request[1] = _id; | 
| request[2] = position; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "setPosition failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "setPosition failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(); | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void setPositionSync(int position) { | 
| @@ -933,19 +1014,23 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| } | 
| } | 
|  | 
| -  void truncate(int length, void callback()) { | 
| +  Future<RandomAccessFile> truncate(int length) { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| List request = new List(3); | 
| request[0] = _FileUtils.kTruncateRequest; | 
| request[1] = _id; | 
| request[2] = length; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "truncate failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "truncate failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(); | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void truncateSync(int length) { | 
| @@ -956,18 +1041,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| } | 
| } | 
|  | 
| -  void length(void callback(int length)) { | 
| +  Future<int> length() { | 
| _ensureFileService(); | 
| +    Completer<int> completer = new Completer<int>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kLengthRequest; | 
| request[1] = _id; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "length failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "length failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(response); | 
| +        completer.complete(response); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| int lengthSync() { | 
| @@ -979,18 +1068,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
| return result; | 
| } | 
|  | 
| -  void flush(void callback()) { | 
| +  Future<RandomAccessFile> flush() { | 
| _ensureFileService(); | 
| +    Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); | 
| List request = new List(2); | 
| request[0] = _FileUtils.kFlushRequest; | 
| request[1] = _id; | 
| _fileService.call(request).then((response) { | 
| if (_isErrorResponse(response)) { | 
| -        _handleErrorResponse(response, "flush failed for file '$_name'"); | 
| +        var e = _exceptionFromResponse(response, | 
| +                                       "flush failed for file '$_name'"); | 
| +        completer.completeException(e); | 
| } else { | 
| -        callback(); | 
| +        completer.complete(this); | 
| } | 
| }); | 
| +    return completer.future; | 
| } | 
|  | 
| void flushSync() { | 
| @@ -1003,49 +1096,20 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { | 
|  | 
| String get name() => _name; | 
|  | 
| -  void set onNoPendingWrites(void handler()) { | 
| -    _onNoPendingWrites = handler; | 
| -    if (_pendingWrites == 0) { | 
| -      _noPendingWriteTimer = new Timer(0, (t) { | 
| -        if (_onNoPendingWrites != null) _onNoPendingWrites(); | 
| -      }); | 
| -    } | 
| -  } | 
| - | 
| void _ensureFileService() { | 
| if (_fileService == null) { | 
| _fileService = _FileUtils.newServicePort(); | 
| } | 
| } | 
|  | 
| -  void _writeEnqueued() { | 
| -    _pendingWrites++; | 
| -    if (_noPendingWriteTimer != null) { | 
| -      _noPendingWriteTimer.cancel(); | 
| -      _noPendingWriteTimer = null; | 
| -    } | 
| -  } | 
| - | 
| -  void  _writeCompleted() { | 
| -    _pendingWrites--; | 
| -    if (_pendingWrites == 0 && _onNoPendingWrites != null) { | 
| -      _onNoPendingWrites(); | 
| -    } | 
| -  } | 
| - | 
| void _checkNotClosed() { | 
| if (_id == 0) { | 
| throw new FileIOException("File closed '$_name'"); | 
| } | 
| } | 
|  | 
| -  String _name; | 
| +  final String _name; | 
| int _id; | 
| -  int _pendingWrites = 0; | 
|  | 
| SendPort _fileService; | 
| - | 
| -  Timer _noPendingWriteTimer; | 
| - | 
| -  Function _onNoPendingWrites; | 
| } | 
|  |