news
Oct 20, 2023

A preview of Unison's improved update process

Rebecca Mark

Unison's process for updating code, merging code, and upgrading library dependencies is the roughest part of the experience right now. So we're fixing it. This post has preview of what you can expect in the next version of Unison.

The original vision for Unison's update process always held promise. Imagine:

  • No conflicts due to semantically meaningless changes like differing whitespace, imports being reordered, or a definition being moved around in the file.
  • No breakage due to definitions being renamed.
  • A codebase that always typechecks, even partway through a complex refactoring.
  • Simple changes are easy to make, and complex refactorings are guided by a helpful copilot.

… but in practice, the implementation of these ideas in the current Unison hasn't been as good as it needs to be. For instance:

  • It's easy to accidentally replace your human readable names with mysterious hashes.
  • There is no indication that conflicts are present unless you run todo.
  • The suggested order of edits sometimes leads you in a circle.
  • There's not a simple experience for upgrading dependencies in a first-class way.

Introducing the new update workflow

You'll primarily be using three commands, edit, update, and merge:

myProj/main> edit foo
myProj/main> update

  ⍟ I've updated these names to your new definition:

    foo : Nat -> Nat -> Text

  I couldn't automatically propagate your changes. I've created a branch for updates and added these definitions to your 'scratch.u' file to resolve:

		bar : Nat -> {IO, Exception} ()

  Do `merge /update134 /main` when finished.

myProj/update134> ... hack hack hack
myProj/update134> update
myProj/update134> merge /update134 /main
myProj/update134> switch /main

In the common case of a type-preserving edit, your change propagates automatically and doesn't create a branch. Otherwise Unison creates a branch for your changes and opens a scratch file with the terms that it couldn't automatically update. Once you fix the type errors in the file, you can run update again and merge the branch back. If you want to abandon the refactoring, you can just delete the branch in progress.

The process for upgrading a library dependency is kicked off with the new upgrade command.

myProj/main> upgrade lib.base_2_0_0 lib.base_3_2_1

Simply specify the current library you want to upgrade and the new target version. If the library changes can be automatically applied, congratulations, you're done! Otherwise, you'll step through the same update process above.

More improvements to come!

The new update process is shipping in the next version of Unison, so stay tuned for more news about this much anticipated feature. In the future, we may do a technical deep-dive into the update process, but we hope this preview of the workflow is cause for celebration. Thank you to the Unison community members who stuck through the old process and still created an impressive suite of libraries. Your perseverance and feedback were instrumental in making this change happen. Come join our friendly slack community for news and conversations about the upcoming release.

Happy coding! 🌻