Skip to main content

Posts

Showing posts with the label Unboxing Packages

New site for Dart news and articles

For the latest Dart news, visit our new blog at  https://medium.com/dartlang .

Unboxing Packages: A Requiem for scheduled_test

Long long ago in the dawning days of Dart, when Future s were new and Stream s unknown, Bob saw the need for a package manager to bring the people together. Together he and I spun formless bits into code and wove that code into pub , which even today carries code into the eager hands of Dartisans. In those olden days, we had no modern marvels such as the twins async and await , and our tests grew heavy and graceless under the weight of their chain() s 1 . So it was that I came up with an idea for a new way of writing tests. Instead of gluing the steps together with the cumbersome Future API, each step would register an asynchronous callback in a queue. Once all the steps were queued up, the library would run them in order. All the API boilerplate would be hidden away from the user, and the tests would look nice and clean . After honing this technique on pub’s tests, I brought it out into its own package, which I called scheduled_test . If this whole idea of queuing up tasks and ...

Unboxing Packages: path

I want to do something a little different with my blog post this week. When I’ve written about packages in the past, I’ve mostly done a high-level overview of their APIs and how they fit into the Dart ecosystem as a whole. But path is one of the very oldest packages in the ecosystem, and any Dart user who’s written any server-side or command-line apps is probably already familiar with the API. So instead of a high-level overview, I want to do a deep dive. I want to talk about why we made the design decisions we made when writing path , and how we implemented our design effectively and efficiently. This post will be as much about how the package was constructed as it is about what the final product looks like. Initial Design It first became clear that Dart needed a solid solution for path manipulation when Bob Nystrom and I first started working on pub . Paths may seem simple on their face, but there’s a lot of hidden complexity when you need to make them work with all the edge...

Unboxing Packages: vm_service_client

Three weeks ago , I wrote about the stream_channel package. Two weeks ago , I wrote about the json_rpc_2 package which is built on top of stream_channel . This week I’ll complete the trifecta by writing about the vm_service_client package, which uses json_rpc_2 in turn—and is a really cool package in its own right! One of the lesser-known corners of the Dart VM is its service protocol , but it’s one of its most powerful components. It uses JSON-RPC 2.0 over WebSockets to allow clients to connect to the VM, inspect its internal state, set breakpoints, and all sorts of neat stuff. If you’ve ever used Observatory for debugging or profiling your Dart code, you’ve been using the service protocol under the hood: that’s how the Observatory web app talks to the VM’s internals. Because the protocol is fully documented and based on a standard underlying protocol, it’s possible for anyone to use from their code. And the vm_service_client package makes it downright easy: it provides a Da...

Unboxing Packages: json_rpc_2

Last week I wrote about the stream_channel package for two-way communication, so this week it seemed natural to move to a package that uses it: json_rpc_2 . This is an implementation of the JSON-RPC 2.0 specification, which is a popular protocol for providing structure and standardization to WebSocket APIs. Although it’s most commonly used with WebSockets, the protocol itself is explicitly independent of the underlying transport mechanism. This makes it a great fit for stream channels, which can be used to represent a two-way stream of JSON objects in a way that works with any underlying mechanism. Thanks to stream channels, JSON-RPC 2.0 can be used across WebSockets , isolates , or any channel a user chooses to wrap. Shared APIs There are three main classes in json_rpc_2 : Client makes requests and receives responses, Server handles requests and returns responses, and Peer does both at once. Because all of these involve two-way communication, they all have the same two ...

Unboxing Packages: stream_channel

The stream_channel package is the youngest I’ve written about so far—the first version was published on 28 January 2016, only three months ago as I write this! But despite its youth, it fills a very important role in the Dart ecosystem by providing a common abstraction for two-way communication. In my article on source_span , I wrote about how important it is for a package ecosystem to provide common conventions that can be used throughout the language. stream_channel is another great example of that. The core API it provides is extremely simple, just two getters and a set of rules for them to follow, but the ability for Dart code to implement protocols independent of the underlying implementation is profound. abstract class StreamChannel < T > { Stream < T > get stream ; StreamSink < T > get sink ; } The test package uses StreamChannel to implement a protocol for running tests that works whether the tests are in an isolate, a separate proce...

Unboxing Packages: async Part 3

We’ve covered individual values and we’ve covered streams , but there are still a few more goodies available in the async package. These don’t fit neatly in either bucket, but when you run into situations that call for them, they’re still plenty useful. Wrappers Just like the collection package , async provides a set of wrapper classes. Each of these classes implements a dart:async class and forwards all calls to an inner instance of that class. This makes it easy for users to provide customized versions of those classes. In fact, the async package itself uses some of its own wrappers. There’s a DelegatingFuture class, of course. There’s also a DelegatingStreamSubscription , and wrappers for every kind of sink or consumer you can name: DelegatingSink , DelegatingEventSink , DelegatingStreamConsumer , and of course DelegatingStreamSink . Of these, DelegatingStreamSink is used most often since it encompasses all the functionality of the other classes. /// A [StreamSin...