If you haven't already heard, Google and Canonical have released a joint statement announcing Linux as a first-class Flutter platform.
You can now build Linux desktop applications using Dart and Flutter. The fact that Canonical is redeveloping the Ubuntu installer in Flutter demonstrates their level of commitment to Flutter.
Canonical is redeveloping the Ubuntu installer in Flutter.
If you are not familiar with Dart, it is a new language released by Google and it is now the fastest growing language on GitHub. Flutter is a cross platform graphical framework written in Dart supporting iOS, android, windows, Linux, Mac OS along with Linux arm support (yes it runs on your raspberry pi).
Even if you have no intent of using Flutter you should look at Dart for building CLI apps.
As an old hack that started my career in C and 6502 assembler and has worked professionally with some dozen or more languages I like to say that 'Dart is Delightful'. It's an elegant language that brings simple solutions to common programming problems.
Dart is Delightful to work with.
At Noojee (the company I work for) we have 10s of thousands of lines of CLI code we use to support our production environment. This CLI code had been written in Bash, Perl, Ruby, Go, Rust, Python... In short, it was a mess and hard to maintain.
When we started working on a Flutter project we fell in love with Dart and saw a path to solve our maintenance problems with our CLI code.
Dart looked to be the perfect tool to replace all of our CLI apps and scripts. No more would we have to deal with archaic Bash and Perl scripts and no more magic Ruby code. We could convert all our scripts to Dart and use a single language for our production GUI and management tooling.
But the real pay off is that Dart is so simple to learn that any of our development team could help maintain CLI scripts and apps with almost no ramp time, try doing that with a Perl script.
Of course life is never as simple as it first looks.
The Future is not so bright
Futures are great for a GUI app, particularly a mobile app, in that you need the GUI to be responsive even when you are fetching data or doing some large calculations.
The problem is that when writing a CLI app you really don't need to have a responsive UI and in fact Futures just make your life harder. Imagine the following code:
The createDir and touch functions are async functions which in Dart are implemented as Futures.
The 'await' statement tells Dart to 'wait' for the function to finish before executing the next line.
Well, in a CLI application, just about every function call would need to be 'awaited' which is just tedious and gives zero benefits.
In fact in our early experiments with Dart, Futures were the cause of a multitude of disasters as it's very easy to forget to await each function (the latest Dart linter does resolve this issue but at the time it was a significant issue).
Imagine in the above example if we had forgotten to await the createDir call. The result would be that the touch call would fail as the /home/me directory wouldn't exist as yet.
waitFor to the rescue
The Dart CLI library has a solution for this; 'waitFor'. The waitFor command essentially tells Dart to change the async function (the Future) into a blocking function which is just perfect for CLI applications.
So we now had a path that made sense but we needed a common library for our team to share code.
And DCli is born
And from that need was born DCli. DCli is a library of functions and classes designed specifically for creating CLI apps and scripts.
A founding principle of the library is that developers should never have to worry about Futures. Internally each of the DCli functions calls waitFor so that you don't need to think about futures. The above code simply becomes:
Don't reinvent the wheel
One of the superpowers of Bash is that it makes it easy to call other CLI applications and process the output:
grep honda cars.txt |head> tophondas.txt
Whilst personally I despise Bash and its less than elegant syntax, you have to give it due credit for its ability to interact with other CLI apps.
In order to be able to replace our Bash scripts without re-inventing every linux app, it was going to be important that we were able to call existing CLI apps just as Bash does.
var hondas =('grep honda carts.txt'|'head').toList();
for(final honda in hondas)
We view the DCli libraries ability to call external apps as so important that the library exposes more than a dozen methods for calling external apps and processing their output.