<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>The Flix Blog</title>
      <link>https://blog.flix.dev/</link>
      <description>The official blog of the Flix programming language.</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://blog.flix.dev/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Fri, 30 Jan 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Making Flix Compiler Errors Helpful and Delightful</title>
          <pubDate>Fri, 30 Jan 2026 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/making-flix-compiler-errors-helpful-and-delightful/</link>
          <guid>https://blog.flix.dev/blog/making-flix-compiler-errors-helpful-and-delightful/</guid>
          <description xml:base="https://blog.flix.dev/blog/making-flix-compiler-errors-helpful-and-delightful/">&lt;p&gt;Inspired by Elm&#x27;s
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elm-lang.org&#x2F;news&#x2F;compiler-errors-for-humans&quot;&gt;Compiler Errors for Humans&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;elm-lang.org&#x2F;news&#x2F;compilers-as-assistants&quot;&gt;Compilers as Assistants&lt;&#x2F;a&gt;,
we recently took a step back and reworked &lt;em&gt;every&lt;&#x2F;em&gt; error message in the Flix compiler.&lt;&#x2F;p&gt;
&lt;p&gt;Here is what you can look forward to in the next version of Flix:&lt;&#x2F;p&gt;
&lt;p&gt;All error messages now have &lt;strong&gt;semantic&lt;&#x2F;strong&gt; syntax highlighting. For single-line errors:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;unexpected-argument.png&quot; alt=&quot;unexpected argument&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And for multi-line errors:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;mismatched-types.png&quot; alt=&quot;mismatched types&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Simple errors are kept brief:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;duplicate-annotation.png&quot; alt=&quot;duplicate annotation&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Whereas complex errors come with explanations and examples:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;missing-implementation.png&quot; alt=&quot;missing implementation&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And, when possible, with suggestions for a fix:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;constructor-not-found.png&quot; alt=&quot;constructor not found&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For very complex errors, we now give an in-depth technical explanation:
&lt;img src=&quot;https:&#x2F;&#x2F;blog.flix.dev&#x2F;blog&#x2F;making-flix-compiler-errors-helpful-and-delightful&#x2F;complex-instance.png&quot; alt=&quot;complex instance&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That&#x27;s all for now.&lt;&#x2F;p&gt;
&lt;p&gt;Hope you enjoy our new colors!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Will LLMs Help or Hurt New Programming Languages?</title>
          <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/will-llms-help-or-hurt-new-programming-languages/</link>
          <guid>https://blog.flix.dev/blog/will-llms-help-or-hurt-new-programming-languages/</guid>
          <description xml:base="https://blog.flix.dev/blog/will-llms-help-or-hurt-new-programming-languages/">&lt;p&gt;Recently, I’ve seen a number of discussions circle around the same question:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Will large language models (LLMs) help or hurt the adoption of new programming languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It is a fair and timely question. As an academic researcher in programming
language design and theory, and as the lead developer of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flix.dev&quot;&gt;Flix programming
language&lt;&#x2F;a&gt;, will I soon be out of a job? Well, maybe not!&lt;&#x2F;p&gt;
&lt;p&gt;In this post, I want to explore whether a modern LLM — here, Claude Code (Opus
4.5) — is able to program in Flix. This is an interesting question because the
amount of training data, e.g. Flix source code, is tiny compared to what exists
for languages like Python and JavaScript.&lt;&#x2F;p&gt;
&lt;p&gt;Given that LLMs are reasonably good at translating between natural languages,
e.g. from English to German, I think there is good reason to believe that they
can also support new programming languages, if those languages are syntactically
and semantically similar to existing ones.&lt;&#x2F;p&gt;
&lt;p&gt;But what happens when a new programming language introduces entirely new syntax
and semantics? For example, the Flix programming language is built around
&lt;strong&gt;effect-oriented programming&lt;&#x2F;strong&gt;. Will Claude be able to use that?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aside:&lt;&#x2F;strong&gt; How much information about Flix is actually in Claude’s training
set? Surely, Anthropic has scooped up our research papers, vacuumed our
documentation, and gobbled our source code. Yet Flix evolves rapidly, and some
information, e.g. from early research papers, may already be slightly
outdated.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;experiment-vibe-coding-tic-tac-toe&quot;&gt;Experiment: Vibe Coding Tic-Tac-Toe&lt;&#x2F;h2&gt;
&lt;p&gt;Today, we will &quot;Vibe Code&quot; (I dislike that term) a Tic-Tac-Toe game in Flix
using Claude Code with the Opus 4.5 model. I chose Tic-Tac-Toe because it is a
well-defined game that requires a moderate use of effects.&lt;&#x2F;p&gt;
&lt;p&gt;My intuition is that writing a new Flix program from scratch is harder for an
LLM because there is no codebase it can gradually evolve, where the exsting
syntax and semantics can serve as examples. There is only the LLM itself and any
information we put into its context.&lt;&#x2F;p&gt;
&lt;p&gt;We begin by creating an empty Flix project:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;$ mkdir tictactoe
$ cd tictactoe
$ flix init
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we are going to help Claude by downloading the entire
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;api.flix.dev&#x2F;&quot;&gt;Flix API&lt;&#x2F;a&gt; reference and the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.flix.dev&#x2F;&quot;&gt;Flix Book&lt;&#x2F;a&gt; documentation:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;$ mkdir -p docs
$ cd docs&#x2F;
$ wget -r -np -k https:&#x2F;&#x2F;api.flix.dev&#x2F;
$ wget -r -np -k https:&#x2F;&#x2F;doc.flix.dev&#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The two downloads take a few minutes. If you’re reading this blog post, you have
my permission to crawl our documentation just like we did above.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we create a &lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt; file with the following text:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;markdown&quot;&gt;# Overview

This is project is written in the Flix programming language.

## Documentation

- **API Reference**: `docs&#x2F;api.flix.dev&#x2F;`
- **Documentation**: `docs&#x2F;doc.flix.dev&#x2F;`

## Flix Compiler Commands

The `flix` compiler is available on PATH and supports the following commands:

- `flix check` - Check code for errors
- `flix run` - Run the project

## Effect System

Flix has an effect system. Documentation is in `docs&#x2F;doc.flix.dev&#x2F;`:

- `effect-system.html` - Core effect system concepts
- `effect-polymorphism.html` - Effect polymorphism
- `effect-oriented-programming.html` - Effect-oriented programming
- `effects-and-handlers.html` - Effects and handlers
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We explicitly instruct Claude on how to run the compiler and what documentation
to consult about the effect system.&lt;&#x2F;p&gt;
&lt;p&gt;We can now start. We run &lt;code&gt;claude&lt;&#x2F;code&gt; and enter &lt;code&gt;plan&lt;&#x2F;code&gt; mode.&lt;&#x2F;p&gt;
&lt;p&gt;We give it the following prompt:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;prompt&quot;&gt;Let us write a tictactoe game in Flix. The game should ask the user for 
a grid size (e.g. 3x3 or 4x4) and then prompt the user for a move. Check 
that the move is valid according to the rules of tictactoe. After each 
player move, the AI makes a valid move. A player wins when they have 
three consecutive x’s or o’s. 

Use the Console effect for user input and output. Use a functional data
structure to store the game state.

Use a recursive function for the game loop.

Use the Logger effect to log all moves in the game. Write your own custom
handler for Logger that writes to a logfile using the FileWrite effect.

Consult the Flix documentation as necessary during planning.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prompt is reasonable, but not very polished. We let Claude chew on the
instructions and it comes back with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;I’ll help you create a Tic-Tac-Toe game in Flix. 

Let me first explore the Flix documentation to understand the effect 
system, Console, and FileWrite APIs.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After a few minutes, we are asked a few questions, including:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;How sophisticated should the AI opponent be?

❯ 1. Random valid moves
     AI picks any random empty cell - simple to implement
  2. Basic strategy
     AI blocks wins and takes winning moves when available
  3. Minimax algorithm
     Optimal AI that never loses - more complex implementation
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Initially, I wanted to pick &lt;strong&gt;(3)&lt;&#x2F;strong&gt;. However, choosing &lt;strong&gt;(1)&lt;&#x2F;strong&gt; is actually more
challenging, because it requires Claude to use the &lt;code&gt;Random&lt;&#x2F;code&gt; effect, whose
handler introduces the primitive &lt;code&gt;NonDet&lt;&#x2F;code&gt; effect. Claude will have to figure
this out on its own.&lt;&#x2F;p&gt;
&lt;p&gt;We make our choice:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;Now I have clear requirements. Let me design the implementation plan.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After about seven minutes of &lt;code&gt;Clauding...&lt;&#x2F;code&gt;, which involves reading both the Flix
API reference and documentation, including &lt;code&gt;Random.html&lt;&#x2F;code&gt; (which looks
promising), Claude reports back with the full plan (which I have abbreviated):&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt; 1. Data Type Definitions 
 ...
 type alias GameState = { board = Board, size = Int32, currentPlayer = Player, moveCount = Int32 }
 type alias Move = { player = Player, row = Int32, col = Int32 }
 ...

 2. Custom Logger Effect

 eff Logger {
     def logMove(m: Move): Unit
 }

 3. Core Functions ...

 4. I&#x2F;O Functions ...

 5. Logger Handler with FileWrite

 def handleLoggerWithFile(logFile: String, f: Unit -&amp;gt; a \ ef): a \ (ef - Logger) + FileWrite =
     run {
         f()
     } with handler Logger {
         def logMove(m, resume) = {
             let line = &amp;quot;${m.player} played at (${m.row + 1}, ${m.col + 1})\n&amp;quot;;
             FileWrite.append({str = line}, logFile);
             resume()
         }
     }

 6. Recursive Game Loop

 def gameLoop(state: GameState): GameResult \ {Console, Logger, Random} = ...

 7. Main Entry Point

 def main(): Unit \ IO =
     let logFile = &amp;quot;game_log.txt&amp;quot;;
     FileWrite.runWithIO(() -&amp;gt;
         handleLoggerWithFile(logFile, () -&amp;gt;
             Random.runWithIO(() -&amp;gt;
                 Console.runWithIO(() -&amp;gt;
                     startGame()
                 )
             )
         )
     ) |&amp;gt; ignore

 Effect handling order (inner to outer): Console -&amp;gt; Random -&amp;gt; Logger -&amp;gt; FileWrite -&amp;gt; IO

 8. Implementation Steps ...

 9. Win Detection Strategy ...

 10. User Input Format ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Overall, the plan looks reasonable, but there are a few issues:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude wants to define its own &lt;code&gt;Logger&lt;&#x2F;code&gt; effect instead of using the &lt;code&gt;Logger&lt;&#x2F;code&gt;
effect from the Standard Library with a custom effect handler.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;main&lt;&#x2F;code&gt; function, while reasonable, does not use the more idiomatic
&lt;code&gt;run-with&lt;&#x2F;code&gt; construct, nor does it use default handlers.&lt;&#x2F;li&gt;
&lt;li&gt;Claude wants to use records for &lt;code&gt;GameState&lt;&#x2F;code&gt; and &lt;code&gt;Move&lt;&#x2F;code&gt;. This typically trips
up Claude because Flix uses &lt;code&gt;rec#field&lt;&#x2F;code&gt; for field selection, not &lt;code&gt;rec.field&lt;&#x2F;code&gt;
which is used for Java interoperability.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We &lt;em&gt;could&lt;&#x2F;em&gt; give Claude instructions to resolve &lt;strong&gt;(1)&lt;&#x2F;strong&gt; and &lt;strong&gt;(2)&lt;&#x2F;strong&gt;, and warn
about &lt;strong&gt;(3)&lt;&#x2F;strong&gt;. But instead, let us see how well Claude does without further
help. Later, we can return and ask Claude to refactor &lt;strong&gt;(1)&lt;&#x2F;strong&gt; and &lt;strong&gt;(2)&lt;&#x2F;strong&gt;. We
proceed:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;The plan is approved. Let me set up a task list and start implementing.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude generates about 350 lines of code and asks for permission to use the Flix
compiler which I grant. The project contains 20+ errors (including parse errors,
name resolution errors, and type errors). Claude says:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;I see several issues. The main ones are:
  1. Logger is already defined in the standard library - 
    I need to rename it to GameLogger
  2. The backtick syntax doesn’t work with qualified names - 
    need to use Int32.mod(index, size)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude has discovered that &lt;code&gt;Logger&lt;&#x2F;code&gt; is already defined, so it (incorrectly)
decides to rename its own &lt;code&gt;Logger&lt;&#x2F;code&gt; to &lt;code&gt;GameLogger&lt;&#x2F;code&gt;. Claude also incorrectly
assumed that Flix has infix syntax for modulo (i.e., &lt;code&gt;x % y&lt;&#x2F;code&gt;), but discovered
that it should instead use &lt;code&gt;Int32.mod&lt;&#x2F;code&gt;. While encountering these issues, Claude
is using both the Flix API reference and documentation to fix them.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aside:&lt;&#x2F;strong&gt; The Flix compiler is highly resilient, so each compilation phase
can proceed to the next, even if the program contains errors. In fact, about
95% of compilation errors are recoverable. As a result, for a program
generated by an LLM with multiple errors, Flix can report all of them at once,
allowing the LLM to fix multiple issues in one pass.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Claude makes several changes and reruns the compiler. Now it gets:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;&amp;gt;&amp;gt; Unable to unify the types: &amp;#39;Player&amp;#39; and &amp;#39;JvmToType(j0)&amp;#39;.

286 |             match state.currentPlayer {
                        ^^^^^^^^^^^^^^^^^^^
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error message is not great — we are working on it — the problem is that the
syntax &lt;code&gt;state.currentPlayer&lt;&#x2F;code&gt; means to read the &lt;code&gt;currentPlayer&lt;&#x2F;code&gt; field on a Java
&lt;em&gt;object&lt;&#x2F;em&gt;, but &lt;code&gt;state&lt;&#x2F;code&gt; is a Flix &lt;em&gt;extensible record&lt;&#x2F;em&gt;. Undauted, Claude continues:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;I see several issues. 

Let me check the Flix documentation for the correct syntax:

I see! In Flix, record field access uses # not .. So state.size 
should be state#size. 

Let me also search for the correct modulo syntax:

 Now I understand. Let me rewrite the file with the correct syntax:
  - Record access: state#size instead of state.size
  - Modulo: Int32.modulo(index, size)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So far, all problems have been purely syntactic.&lt;&#x2F;p&gt;
&lt;p&gt;But now, Claude runs into its first effect-related issues:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;...

 I see! Key insights:
  1. Random.runWithIO introduces NonDet effect (which is uninterpretable)
  2. Random.runWithSeed(seed, f) handles Random without NonDet
  3. No do keyword - effect operations are called directly
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are two issues: First, the &lt;code&gt;Random.runWithIO&lt;&#x2F;code&gt; handler has &lt;strong&gt;both&lt;&#x2F;strong&gt; the
&lt;code&gt;IO&lt;&#x2F;code&gt; and &lt;code&gt;NonDet&lt;&#x2F;code&gt; effects which must be part of the effect signature of &lt;code&gt;main&lt;&#x2F;code&gt;.
Second, Flix no longer uses the &lt;code&gt;do&lt;&#x2F;code&gt; keyword to invoke an effect operation.
Surprisingly, Claude quickly overcomes both issues. A single error remains:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;Good progress! Just one error left - 
    String.split already returns a List, not a Vector. Let me fix that:
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And done! The program compiles. Lets try to run it:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;$ flix run 

Welcome to Tic-Tac-Toe!
======================
Enter grid size (3-9):
3

Starting 3x3 game. You are X, AI is O.
Get 3 in a row to win!

   1 2 3
1  . . .
2  . . .
3  . . .
Your turn (X):
Enter your move (row col), e.g., &amp;#39;1 2&amp;#39;:
1 2 
   1 2 3
1  . X .
2  . . .
3  . . .
AI is thinking...
AI plays at (3, 3)
   1 2 3
1  . X .
2  . . .
3  . . O

... 

   1 2 3
1  X X O
2  X X .
3  O . O
AI is thinking...
AI plays at (3, 2)
   1 2 3
1  X X O
2  X X .
3  O O O
Player O wins!
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Recall that we asked Claude to log all moves. There is a &lt;code&gt;game_log&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;txt&quot;&gt;=== Tic-Tac-Toe Game Log ===
X played at (1, 2)
O played at (3, 3)
X played at (1, 1)
O played at (1, 3)
X played at (2, 2)
O played at (3, 1)
X played at (2, 1)
O played at (3, 2)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looks alright!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;refactoring-the-game&quot;&gt;Refactoring the Game&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s return to our TODO list. We wanted Claude to address two issues:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude was using its own &lt;code&gt;GameLogger&lt;&#x2F;code&gt; effect, but we wanted it to use the built-in &lt;code&gt;Logger&lt;&#x2F;code&gt; effect with a custom handler.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;main&lt;&#x2F;code&gt; entry point is correct, but written in a non-idiomatic style.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let’s start with &lt;strong&gt;(1)&lt;&#x2F;strong&gt;. We prompt Claude:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;prompt&quot;&gt;Refactor the project to use the built-in Logger effect.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude consults the Flix API reference and documentation.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;I now understand the built-in Logger API. The refactoring involves:

  1. Removing the custom GameLogger effect
  2. Using Logger.info(message) instead of GameLogger.logMove(move)
  3. Writing a custom handler for the built-in Logger that writes to
  file using FileWrite
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notably Claude has figured out that it has to write its own handler for &lt;code&gt;Logger&lt;&#x2F;code&gt;
which &lt;em&gt;itself&lt;&#x2F;em&gt; uses the &lt;code&gt;FileWrite&lt;&#x2F;code&gt; effect.&lt;&#x2F;p&gt;
&lt;p&gt;I ask Claude to continue. The refactoring is successful: the &lt;code&gt;GameLogger&lt;&#x2F;code&gt; effect
is removed and &lt;code&gt;Logger&lt;&#x2F;code&gt; is used. The new custom handler is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;&#x2F;&#x2F; Named &amp;quot;handleLoggerWithFile&amp;quot; but renamed to h to fit on the screen.
def h(logFile: String, f: Unit -&amp;gt; a \ ef): a \ (ef - Logger) + FileWrite =
    run {
        f()
    } with handler Logger {
        def log(severity, msg, resume) = {
            let line = &amp;quot;[${severity}] ${msg}\n&amp;quot;;
            FileWrite.append({str = line}, logFile);
            resume()
        }
    }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude has figured out the correct syntax for an effect polymorphic function
that handles &lt;code&gt;Logger&lt;&#x2F;code&gt; while causing the &lt;code&gt;FileWrite&lt;&#x2F;code&gt; effect, i.e. the signature:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def h(logFile: String, f: Unit -&amp;gt; a \ ef): a \ (ef - Logger) + FileWrite = 
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Impressive!&lt;&#x2F;p&gt;
&lt;p&gt;Next, I want to fix &lt;strong&gt;(2)&lt;&#x2F;strong&gt;, i.e. improve the style of &lt;code&gt;main&lt;&#x2F;code&gt;. I prompt:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;prompt&quot;&gt;Refactor main to use default handlers for the built-in effects.

Use run-with for the Logger effect and custom handler.

See @docs&#x2F;doc.flix.dev&#x2F;default-handlers.html for documentation.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point the dreaded &quot;compacting conversation&quot; happens. Let’s see how it goes.&lt;&#x2F;p&gt;
&lt;p&gt;After a bit of &lt;code&gt;Clauding...&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;claude&quot;&gt;The error shows that `Random` doesn’t have a default handler.
Let me check the documentation more carefully:

Read(docs&#x2F;doc.flix.dev&#x2F;default-handlers.html)
⎿  Read 284 lines

I see - the documentation shows Clock, Env, and Logger have 
default handlers, but Random may not. Let me check the Random API:

Search(pattern: &amp;quot;@DefaultHandler&amp;quot;, path: &amp;quot;docs&#x2F;api.flix.dev&amp;quot;)
⎿  Found 10 lines (ctrl+o to expand)

Console and Logger have default handlers, but Random does not. 
I need to keep Random.runWithIO() explicit:
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The refactoring completes successfully. The new &lt;code&gt;main&lt;&#x2F;code&gt; is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def main(): Unit \ {Console, IO, NonDet} =
    let logFile = &amp;quot;game_log.txt&amp;quot;;
    &#x2F;&#x2F; Initialize log file
    discard FileWrite.runWithIO(() -&amp;gt; FileWrite.write({str = &amp;quot;=== Tic-Tac-Toe Game Log ===\n&amp;quot;}, logFile));
    &#x2F;&#x2F; Run the game - Console uses default handler, Random&#x2F;Logger&#x2F;FileWrite need explicit handlers
    discard FileWrite.runWithIO(() -&amp;gt;
        handleLoggerWithFile(logFile, () -&amp;gt;
            Random.runWithIO(() -&amp;gt;
                startGame()
            )
        )
    )
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Ugh.&lt;&#x2F;strong&gt; &lt;em&gt;This is not good.&lt;&#x2F;em&gt; While the code is technically correct, its
structure is terrible. A few things have gone wrong, partly due to my own
instructions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I asked Claude to use default handlers for all effects. However, the
&lt;code&gt;FileWrite&lt;&#x2F;code&gt; effect has no default handler because it can fail. In particular,
&lt;code&gt;FileWrite.runWithIO&lt;&#x2F;code&gt; returns a &lt;code&gt;Result[IoError, Unit]&lt;&#x2F;code&gt;. Claude, in its
infinite wisdom, decided that we should simply discard the &lt;code&gt;Result&lt;&#x2F;code&gt; 🤡&lt;&#x2F;li&gt;
&lt;li&gt;I asked Claude to use the &lt;code&gt;run-with&lt;&#x2F;code&gt; construct, but it did not.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let us try again, but this time we will be more specific:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;prompt&quot;&gt;I want you to refactor main. I want it to use a single run-with construct.
Let bind the result to a local variable called r. Inside the run, you
should call FileWrite.write and startGame. You should then use &amp;quot;with&amp;quot; to
install the handlers handleLoggerWithFile and Random.runWithIO. Lastly,
pattern match on the result r, and print an error message using
Console.println if it is Result.Err.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now Claude consults the Flix documentation to learn about &lt;code&gt;run-with&lt;&#x2F;code&gt; and produces:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;def main(): Unit \ {Console, IO, NonDet} =
    let logFile = &amp;quot;game_log.txt&amp;quot;;
    let r = run {
        FileWrite.write({str = &amp;quot;=== Tic-Tac-Toe Game Log ===\n&amp;quot;}, logFile);
        startGame()
    } with handleLoggerWithFile(logFile)
      with Random.runWithIO
      with FileWrite.runWithIO;
    match r {
        case Result.Err(e) =&amp;gt; Console.println(&amp;quot;Error: ${e}&amp;quot;)
        case Result.Ok(_) =&amp;gt; ()
    }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Much better. This example shows that Claude is able to program effectively (no
pun intended!) with a rich collection of effects. The program uses the
&lt;code&gt;Console&lt;&#x2F;code&gt;, &lt;code&gt;FileWrite&lt;&#x2F;code&gt;, &lt;code&gt;Logger&lt;&#x2F;code&gt;, and &lt;code&gt;Random&lt;&#x2F;code&gt; effects. Embracing the richness
of the domain, we handle the &lt;code&gt;Logger&lt;&#x2F;code&gt; effect using &lt;code&gt;handleLoggerWithFile&lt;&#x2F;code&gt;, which
in turn causes the &lt;code&gt;FileWrite&lt;&#x2F;code&gt; effect. We then handle the remaining effects
using their associated &lt;code&gt;runWithIO&lt;&#x2F;code&gt; handlers, introducing the &lt;em&gt;primitive&lt;&#x2F;em&gt; effects
&lt;code&gt;IO&lt;&#x2F;code&gt; and &lt;code&gt;NonDet&lt;&#x2F;code&gt;. Lastly, &lt;code&gt;Console&lt;&#x2F;code&gt; is handled by its default effect handler.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aside:&lt;&#x2F;strong&gt; This program illustrates how, in effect-oriented programming
languages, effects are pushed outwards toward &lt;code&gt;main&lt;&#x2F;code&gt;, where they must be
handled. In other words, all dependency injection and plumbing typically
happens near &lt;code&gt;main&lt;&#x2F;code&gt;, while most of the program remains pure modulo effects.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We might be disappointed that &lt;code&gt;main&lt;&#x2F;code&gt; is still fairly complex. Why not use
default handlers for &lt;code&gt;FileWrite&lt;&#x2F;code&gt; and &lt;code&gt;Random&lt;&#x2F;code&gt;? For &lt;code&gt;Random&lt;&#x2F;code&gt;, Flix has a
limitation that prevents it. For &lt;code&gt;FileWrite&lt;&#x2F;code&gt;, errors are pushed to the handler
rather than the call site, so we must handle them ourselves (here, by printing
to the terminal). We could have used &lt;code&gt;FileWriteWithResult&lt;&#x2F;code&gt;, forcing the game to
handle errors and allowing a default handler in &lt;code&gt;main&lt;&#x2F;code&gt;, but that would add
complexity to the game logic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;game-api-and-excerpts&quot;&gt;Game API and Excerpts&lt;&#x2F;h2&gt;
&lt;p&gt;For reference, here are some of the function signatures of the game:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def aiMove(state: GameState): (Int32, Int32) \ Random =
def cellToChar(cell: Cell): String =
def displayBoard(state: GameState): Unit \ Console =
def parseInt(s: String): Option[Int32] =
def promptGridSize(): Int32 \ Console =
def promptMove(state: GameState): (Int32, Int32) \ Console =
def gameLoop(state: GameState): GameResult \ {Console, Logger, Random} =
def startGame(): Unit \ {Console, Logger, Random} =
def main(): Unit \ {Console, IO, NonDet} =
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude has done a solid job breaking the game into smaller functions, each using
only the effects it needs. Notably, the &lt;code&gt;IO&lt;&#x2F;code&gt; effect is only used by &lt;code&gt;main&lt;&#x2F;code&gt;. This
is the essence of &lt;em&gt;effect-oriented programming&lt;&#x2F;em&gt;, and Claude has achieved it.&lt;&#x2F;p&gt;
&lt;p&gt;We can look at a few examples:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def startGame(): Unit \ {Console, Logger, Random} =
    Console.println(&amp;quot;Welcome to Tic-Tac-Toe!&amp;quot;);
    Console.println(&amp;quot;======================&amp;quot;);
    let size = promptGridSize();
    let state = initGameState(size);
    Console.println(&amp;quot;&amp;quot;);
    Console.println(&amp;quot;Starting ${size}x${size} game. You are X, AI is O.&amp;quot;);
    Console.println(&amp;quot;Get 3 in a row to win!&amp;quot;);
    Console.println(&amp;quot;&amp;quot;);
    discard gameLoop(state)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here &lt;code&gt;startGame&lt;&#x2F;code&gt; has the &lt;code&gt;Console&lt;&#x2F;code&gt;, &lt;code&gt;Logger&lt;&#x2F;code&gt;, and &lt;code&gt;Random&lt;&#x2F;code&gt; effects. &lt;code&gt;Console&lt;&#x2F;code&gt; is
used directly, whereas &lt;code&gt;Logger&lt;&#x2F;code&gt; and &lt;code&gt;Random&lt;&#x2F;code&gt; are used by &lt;code&gt;gameLoop&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;And here is the &lt;code&gt;promptGridSize&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def promptGridSize(): Int32 \ Console =
    Console.println(&amp;quot;Enter grid size (3-9):&amp;quot;);
    let input = Console.readln();
    match parseInt(String.trim(input)) {
        case Some(n) if n &amp;gt;= 3 and n &amp;lt;= 9 =&amp;gt; n
        case _ =&amp;gt;
            Console.println(&amp;quot;Invalid size. Please enter a number between 3 and 9.&amp;quot;);
            promptGridSize()
    }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h2&gt;
&lt;p&gt;I think the key lessons are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Giving Claude access to the newest Flix API reference and documentation is
invaluable. Claude is surprisingly good at consulting both whenever it needs
to use a feature or runs into a problem.&lt;&#x2F;li&gt;
&lt;li&gt;Giving Claude access to the compiler is must. Furthermore, the Flix compiler’s
resilience allows Claude to discover and correct multiple issues in one pass.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Claude’s code style isn’t great. I’d call it unopinionated, which feels a bit
odd—but perhaps makes sense, given that there isn’t yet a defined Flix style. In
the future, I’d like to explore whether giving Claude a style guide would help.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;Returning to the central question of this blog post:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Will large language models (LLMs) help or hurt the adoption of new programming languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Based on my experience over the past six months, I’m convinced that LLMs will
only help the adoption of new languages. We’ve seen that by giving Claude access
to the Flix API reference, documentation, and compiler, it can become a capable
Flix programmer.&lt;&#x2F;p&gt;
&lt;p&gt;While Claude makes silly syntax mistakes, which would not happen for Python or
JavaScript, it can usually overcome them. More impressively, Claude is already
capable of &lt;em&gt;effect-oriented programming&lt;&#x2F;em&gt;. It can write functions that use
effects, functions that handle effects, and even intricate effect polymorphic
functions such as &lt;code&gt;handleLoggerWithFile&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, I think, the future for new programming languages is as bright as ever.&lt;&#x2F;p&gt;
&lt;p&gt;Until next time, happy Clauding.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Effect Systems vs Print Debugging: A Pragmatic Solution</title>
          <pubDate>Mon, 15 Sep 2025 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/effect-systems-vs-print-debugging/</link>
          <guid>https://blog.flix.dev/blog/effect-systems-vs-print-debugging/</guid>
          <description xml:base="https://blog.flix.dev/blog/effect-systems-vs-print-debugging/">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;Every lie we tell incurs a debt to the truth. Sooner or later, that debt is paid.&quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;— Valery Legasov (&lt;em&gt;Jared Harris, Chernobyl 2019&lt;&#x2F;em&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;Lying to a &lt;strong&gt;type system&lt;&#x2F;strong&gt; works the same way: the truth eventually comes out.
In memory-safe languages, that usually means as a runtime error (e.g. a
&lt;code&gt;ClassCastException&lt;&#x2F;code&gt;, a &lt;code&gt;TypeError: foo is not a function&lt;&#x2F;code&gt;, and so on). In
memory-unsafe languages, the consequences can be more dire: corrupted data,
segmentation faults, or arbitrary code execution. Nevertheless, if we are in a
memory-safe language, we might not feel too bad about lying to the type
system...&lt;&#x2F;p&gt;
&lt;p&gt;But what happens when you lie to the &lt;strong&gt;effect system&lt;&#x2F;strong&gt;? Nothing good.&lt;&#x2F;p&gt;
&lt;p&gt;To understand why, let us examine how the Flix compiler uses the effect system:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Dead code elimination:&lt;&#x2F;strong&gt; Flix uses the effect system to identify expressions,
statements, and let-bindings that have no side effects and whose results are
unused. The compiler removes such code, improving performance and reducing
binary size.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Inlining and value propagation:&lt;&#x2F;strong&gt; Flix also uses the effect system to
determine which let-bindings can be safely inlined without changing program
semantics. This enables constant folding and closure elimination.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Automatic parallelization:&lt;&#x2F;strong&gt; The Flix compiler, in cooperation with the Flix
Standard Library, automatically parallelizes a selected set of higher-order
functions when their arguments are pure, and when parallel evaluation preserves
program semantics.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Separating control-pure from control-impure code:&lt;&#x2F;strong&gt; Flix uses effect tracking
to distinguish code that may trigger effects and handlers from purely
computational code. Control-pure code is compiled without capturing the
delimited continuation, while control-impure code includes the machinery
required to reify the stack.&lt;&#x2F;p&gt;
&lt;p&gt;These are scary program transformations!&lt;&#x2F;p&gt;
&lt;p&gt;Hence, when a Flix programmer writes a function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def add(x: Int32, y: Int32): Int32 \ { } = x + y
                                  &#x2F;&#x2F; ^^^ empty effect set
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We — the Flix language designers — are downright paranoid about ensuring that
the effects of the function are not a lie. &lt;em&gt;But surely one little white lie is
okay&lt;&#x2F;em&gt;, you suggest, as you carelessly add that &lt;code&gt;unchecked_cast&lt;&#x2F;code&gt; to your program,
while I look on with dark visions of unspeakable cosmic horror.&lt;&#x2F;p&gt;
&lt;p&gt;Interlude...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;print-debugging&quot;&gt;Print Debugging&lt;&#x2F;h2&gt;
&lt;p&gt;One beautiful autumn afternoon, Jim was sitting in front of his computer.
Outside, the leaves were turning brilliant shades of orange, while inside, a
freshly brewed cup of coffee sat beside him. He had just finished reading a blog
post on HackerNews about a new programming language with a type and effect
system: Flix.&lt;&#x2F;p&gt;
&lt;p&gt;Intrigued, he downloaded the compiler and typed:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def main(): Int32 \ IO = 
    println(&amp;quot;Hello World!&amp;quot;);
    sum(123, 456)

def sum(x: Int32, y: Int32): Int32 =
    let result = x + y;
    println(&amp;quot;The sum of ${x} and ${y} is ${result}&amp;quot;);
    result
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Running the Flix compiler, Jim was confronted with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;❌ -- Type Error --

&amp;gt;&amp;gt; Unable to unify the effect formulas: &amp;#39;IO&amp;#39; and &amp;#39;Pure&amp;#39;.

6 |&amp;gt; def sum(x: Int32, y: Int32): Int32 = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dismayed, Jim poked around a bit but couldn’t get the program to work.
Frustrated, he returned to HackerNews and posted a comment:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ever tried adding a simple print statement for debugging purposes while coding
in effectful lang? compiler: &quot;NNNOOOO!!!! THIS IS AN ERROR; I WILL NEVER
COMPILE THIS NONSENSE YOU MUST SPECIFY THE &lt;code&gt;CONSOLE&lt;&#x2F;code&gt; EFFECT WAAARGH&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;being-a-programming-language-designer-is-hard&quot;&gt;Being a Programming Language Designer is Hard&lt;&#x2F;h2&gt;
&lt;p&gt;The art of programming language design is to balance contradictory requirements:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Programmers expect lightning-fast compilation, but also deep, aggressive
compiler optimizations. (&quot;The compiler is too slow!&quot; vs. &quot;Surely the compiler
will optimize that away!&quot;)&lt;&#x2F;li&gt;
&lt;li&gt;Programmers want expressive type systems, but also intuitive and helpful error
messages. (&quot;What do you mean a skolem variable escapes its scope???&quot;)&lt;&#x2F;li&gt;
&lt;li&gt;Programmers want type inference, but also simple type error messages (&quot;What do
you mean you can&#x27;t unify these types?&quot;)&lt;&#x2F;li&gt;
&lt;li&gt;Programmers want escape hatches for everything, but nothing must ever break.
(&quot;What do you mean turning off the fuel for the engines crashes the plane? I
thought you said this was a safe airplane?!&quot;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Returning to earth: we may be academics, but &lt;strong&gt;we are trying to build a real
programming language. That means listening to our users and that means
we have to support print debugging.&lt;&#x2F;strong&gt; The question is &lt;em&gt;how&lt;&#x2F;em&gt;?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;print-debugging-attempt-1&quot;&gt;Print-Debugging — Attempt #1&lt;&#x2F;h2&gt;
&lt;p&gt;Consider if we introduce a special function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;mod Debug {
    pub def dprintln(x: a): Unit with ToString[a] =
        unchecked_cast(println(x) as _ \ {}) 
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we use an &lt;code&gt;unchecked_cast&lt;&#x2F;code&gt; to discard the &lt;code&gt;IO&lt;&#x2F;code&gt; effect of &lt;code&gt;println&lt;&#x2F;code&gt;. That
is, we &lt;em&gt;lie&lt;&#x2F;em&gt; to the effect system.&lt;&#x2F;p&gt;
&lt;p&gt;While our special &lt;code&gt;dprintln&lt;&#x2F;code&gt; function type and effect checks, it does not work
well.&lt;&#x2F;p&gt;
&lt;p&gt;If we attempt to use it as follows:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def sum(x: Int32, y: Int32): Int32 =
    let result = x + y;
    Debug.dprintln(&amp;quot;The sum of ${x} and ${y} is ${result}&amp;quot;);
    result
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Flix compiler rejects our program with the error:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;❌ -- Redundancy Error --

&amp;gt;&amp;gt; Useless expression: It has no side-effect(s) and its result is discarded.

11 |         Debug.dprintln(&amp;quot;The sum of ${x} and ${y} is ${result}&amp;quot;);
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
             useless expression.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The compiler &lt;em&gt;correctly&lt;&#x2F;em&gt; reports that &lt;code&gt;dprintln&lt;&#x2F;code&gt; is a useless expression: it has
no observable effects and its result is ignored. This redundancy check is
normally helpful for catching bugs, but in this case it prevents our use of
&lt;code&gt;dprintln&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can try to work around this check with a small trick:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def sum(x: Int32, y: Int32): Int32 =
    let result = x + y;
    let _ = Debug.dprintln(&amp;quot;The sum of ${x} and ${y} is ${result}&amp;quot;);
    result
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By introducing a let binding with a wildcard name, the redundancy checker is
satisfied and the program now compiles.&lt;&#x2F;p&gt;
&lt;p&gt;However, when we run the program... nothing is printed!&lt;&#x2F;p&gt;
&lt;p&gt;Now, the optimizer detects that the let-bound expression has no side effects and
that its variable is unused, so it removes it. Normally this is desirable; we
want the optimizer to eliminate dead code, but here it gets in our way.&lt;&#x2F;p&gt;
&lt;p&gt;It seems we are stuck. There are two paths forward:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We could try to equip the optimizer with knowledge of print debugging
statements. In that case, we would track these &quot;effects-that-are-not-effects&quot;
and avoid treating them as pure expressions. The problem with this approach is
that it would have to handle the entire language—e.g., lambda expressions,
higher-order functions, and polymorphism. In effect (no pun intended), we
would essentially be re-implementing an ad hoc effect system inside the
optimizer.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;We could decide to &lt;em&gt;disable&lt;&#x2F;em&gt; the optimizer during development. The problem
with that is threefold: (a) it would cause a massive slowdown in runtime
performance, (b) somewhat surprisingly, it would also make the Flix compiler
itself run &lt;em&gt;slower&lt;&#x2F;em&gt;, since dead code elimination and other optimizations
actually speed up the backend, and (c) it would be fertile ground for compiler
bugs, because instead of one battle-tested compiler pipeline, there would be two
pipelines to develop and maintain.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Neither option is really acceptable to us.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;print-debugging-attempt-2&quot;&gt;Print-Debugging — Attempt #2&lt;&#x2F;h2&gt;
&lt;p&gt;What we need is a better lie: one with a different set of trade-offs.&lt;&#x2F;p&gt;
&lt;p&gt;We introduce a &lt;code&gt;Debug&lt;&#x2F;code&gt; effect and use it for &lt;code&gt;dprintln&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;eff Debug { &#x2F;* empty -- marker effect *&#x2F; }

mod Debug {
    pub def dprintln(x: a): Unit \ Debug with ToString[a] = ...
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We no longer lie about &lt;code&gt;dprintln&lt;&#x2F;code&gt;. Calling it now has the &lt;code&gt;Debug&lt;&#x2F;code&gt; effect.&lt;&#x2F;p&gt;
&lt;p&gt;We can use it to debug our &lt;code&gt;sum&lt;&#x2F;code&gt; function from earlier:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def sum(x: Int32, y: Int32): Int32 =
    let result = x + y;
    Debug.dprintln(&amp;quot;The sum of ${x} and ${y} is ${result}&amp;quot;);
    result
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The implementation of &lt;code&gt;sum&lt;&#x2F;code&gt; is a let-expression whose body is a
statement-expression. Because of the call to &lt;code&gt;dprintln&lt;&#x2F;code&gt;, the inferred effect of
both is &lt;code&gt;Debug&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We are now back to the original problem: The &lt;code&gt;Debug&lt;&#x2F;code&gt; effect is incompatible with
the declared type and effect signature of &lt;code&gt;sum&lt;&#x2F;code&gt; (i.e., &lt;code&gt;sum&lt;&#x2F;code&gt; having the empty
effect set). However, instead of changing the signature of &lt;code&gt;dprintln&lt;&#x2F;code&gt; or &lt;code&gt;sum&lt;&#x2F;code&gt;,
&lt;strong&gt;we will change the &lt;em&gt;effect system&lt;&#x2F;em&gt; to allow the absence of the &lt;code&gt;Debug&lt;&#x2F;code&gt;
effect&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When a programmer writes a type and effect signature like:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def downloadUrl(x: Int32): Unit \ {FileWrite, Http} = exp
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We first check if &lt;code&gt;exp&lt;&#x2F;code&gt; can be type-checked with the signature:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Int32 -&amp;gt; Unit \ {FileWrite, Http}&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If it cannot, we retry with the signature:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Int32 -&amp;gt; Unit \ {FileWrite, Http, Debug}&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If that works, we consider the function well-typed, but crucially, we do &lt;em&gt;not&lt;&#x2F;em&gt;
update the signature of &lt;code&gt;downloadUrl&lt;&#x2F;code&gt;. Consequently, everywhere &lt;code&gt;downloadUrl&lt;&#x2F;code&gt; is
used, it is still typed as if it only has the &lt;code&gt;FileWrite&lt;&#x2F;code&gt; and &lt;code&gt;Http&lt;&#x2F;code&gt; effects.&lt;&#x2F;p&gt;
&lt;p&gt;The advantages of this implementation are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;We can use &lt;code&gt;dprintln&lt;&#x2F;code&gt; anywhere in a function and it just works.&lt;&#x2F;li&gt;
&lt;li&gt;We can add &lt;code&gt;dprintln&lt;&#x2F;code&gt; anywhere without having to change the signature of the
function nor the signatures of any callers.&lt;&#x2F;li&gt;
&lt;li&gt;We can be sure that the optimizer will leave our &lt;code&gt;dprintln&lt;&#x2F;code&gt; calls intact.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are two minor downsides. First, adding a &lt;code&gt;dprintln&lt;&#x2F;code&gt; marks an expression as
impure, effectively disabling the optimizer for that expression and its parent
expressions. Still, this is far less invasive than disabling the optimizer for
the entire program. Second, because the &lt;code&gt;Debug&lt;&#x2F;code&gt; effect is hidden from the
function’s signature, calls to that function inside other functions might be
moved or even eliminated. On the bright side, this ensures that a &lt;code&gt;dprintln&lt;&#x2F;code&gt;
only prints if the function is actually called!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Development vs. Production Mode.&lt;&#x2F;strong&gt; We don’t want published packages to (a) lie
to the type and effect system, or (b) contain print debugging statements. Hence,
when the compiler is run in production mode, we disable the lie that allows the
implicit &lt;code&gt;Debug&lt;&#x2F;code&gt; effect. As a result, using &lt;code&gt;dprintln&lt;&#x2F;code&gt; in production mode causes
a compilation error.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;addendum-look-ma-no-macros&quot;&gt;Addendum: Look Ma: No Macros!&lt;&#x2F;h2&gt;
&lt;p&gt;Rust has a beautiful &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;macro.dbg.html&quot;&gt;&lt;code&gt;dbg!&lt;&#x2F;code&gt; macro&lt;&#x2F;a&gt; which works like this:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;rust&quot;&gt;let a = 2;
let b = dbg!(a * 2) + 1;
&#x2F;&#x2F;      ^-- prints: [src&#x2F;main.rs:2:9] a * 2 = 4
assert_eq!(b, 5);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since the macro has access to the syntax tree, it can print the file name, line,
column, and the original expression. Flix does not currently support macros (and
we would not introduce them solely for this purpose). However, we can achieve
part of this functionality using a &lt;strong&gt;debug string interpolator&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For example, we can write:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;use Debug.dprintln

def main(): Unit \ IO = 
    let result = sum(123, 456);
    println(&amp;quot;The sum is: ${result}&amp;quot;)

def sum(x: Int32, y: Int32): Int32 = 
    dprintln(d&amp;quot;x = ${x}, y = ${y}&amp;quot;);
    x + y
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the debug string interpolator &lt;code&gt;d&quot;x = ${x}, y = ${y}&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Running the program prints:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;sh&quot;&gt;[Main.flix:8] x = 123, y = 456                         
The sum is: 579
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We get the file name and line number for the small cost of a single &lt;code&gt;d&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s all for now.&lt;&#x2F;p&gt;
&lt;p&gt;Until next time, happy hacking.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>In Defense of Programming Languages</title>
          <pubDate>Thu, 01 Jul 2021 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/in-defense-of-programming-languages/</link>
          <guid>https://blog.flix.dev/blog/in-defense-of-programming-languages/</guid>
          <description xml:base="https://blog.flix.dev/blog/in-defense-of-programming-languages/">&lt;p&gt;This blog post is written in defense of programming language enthusiasts; whether they are compiler hackers, programming language hobbyists, industry professionals, or academics.&lt;&#x2F;p&gt;
&lt;p&gt;In this blog post, I want to examine the discourse around programming languages and especially how new programming languages are received. My hope is to improve communication between programming languages designers and software developers. I understand that we cannot all agree, but it would be fantastic if everyone could at least try to be friendly, to be intellectually curious, and to give constructive feedback!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-few-quotes-from-the-internet&quot;&gt;A Few Quotes from the Internet&lt;&#x2F;h2&gt;
&lt;p&gt;Let me set the stage with a few quotes from social media tech sites (e.g. Reddit, HackerNews, Twitter, etc.). I have lightly edited and anonymized the following quotes:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Great! Yet-another-programming-language™. This is exactly what we need; the gazillion of existing programming languages is not enough!&quot;&lt;&#x2F;p&gt;
&lt;p&gt;— Furious Panda via Reddit&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;This is – by far – the worst syntax I have ever seen in a functional language!&quot;&lt;&#x2F;p&gt;
&lt;p&gt;— Irate Penguin via Reddit&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;The language is probably great from a technical point of view, but unless Apple, Google, Mozilla, or Microsoft is on-board it is pointless.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;— Angry Beaver via HackerNews&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;How can anyone understand such weird syntax? I hate all these symbols.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;— Bitter Turtle via Reddit&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;The examples all look horrible. The site looks horrible. This needs a lot of work before it gets close to anything I would even consider using.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;— Enraged Koala via Twitter&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;While all of the above quotes are in response to news about the Flix programming language (on whose website you are currently reading this blog post), depressingly similar comments are frequently posted in response to news about other new programming languages.&lt;&#x2F;p&gt;
&lt;p&gt;Why do people post such comments? And what can be done about it?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-do-such-comments-come-from&quot;&gt;Where do such comments come from?&lt;&#x2F;h2&gt;
&lt;p&gt;I think there are two reasons which are grounded in legitimate concerns:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fatigue:&lt;&#x2F;strong&gt; I think there is a sense that there are new programming languages coming out all the time. Paradoxically, I think there is both a dread of having to keep up with ever-changing programming languages (and other technologies) and simultaneously a sense that these new programming languages are all the same.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Speech:&lt;&#x2F;strong&gt; Programming languages are the material with which we craft programs: It is our way of &quot;speaking&quot; algorithmically. They are about what we say, how we say it, and even what can be said. Like prose, what is beautiful and elegant is in the eye of the beholder. It is not surprising then that when a new programming language comes along and suggests a different form of expression that some may have strong reactions to.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course there are also internet trolls; but let us ignore them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-point-by-point-rebuttal&quot;&gt;A Point-by-Point Rebuttal&lt;&#x2F;h2&gt;
&lt;p&gt;I want to give a point-by-point rebuttal to the most common refrains heard whenever a new programming language is proposed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-we-really-need-new-programming-languages&quot;&gt;Do we really need new programming languages?&lt;&#x2F;h3&gt;
&lt;p&gt;The Flix &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flix.dev&#x2F;faq&#x2F;&quot;&gt;FAQ&lt;&#x2F;a&gt; joking responds to this question with a rhetorical question: &lt;em&gt;Do we really need safer airplanes? Do we really need electric cars? Do we really need more ergonomic chairs?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think it is a valid argument. We want better programming languages because we want to offer software developers better tools to write their programs. You might say that existing programming languages already have all the feature we need, but I think that there are exciting developments; both brand new ideas and old research ideas that are making their way into new programming languages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Safety:&lt;&#x2F;strong&gt; region-based memory management, lifetimes, ownership types, linear types, 2nd class values, and capabilities.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Expressiveness:&lt;&#x2F;strong&gt; union and intersection types, polymorphic effect systems, algebraic effects, type-driven development, increasingly powerful type inference.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Development Experience:&lt;&#x2F;strong&gt; the Visual Studio Code ecosystem, the language server protocol, GitHub code-spaces.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I don&#x27;t think we are anywhere near to the point where programming languages are as good as they are ever going to get. On the contrary, I think we are still in the infancy of programming language design.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;all-programming-languages-are-the-same&quot;&gt;All programming languages are the same&lt;&#x2F;h3&gt;
&lt;p&gt;I strongly disagree. I think we are experiencing a period of programming language fragmentation after a long period of consolidation and stagnation. For the last 15-years or so, the industry has been dominated by C, C++, C# and Java. The market share of these programming languages was always increasing and they were the default safe choice for new software projects.&lt;&#x2F;p&gt;
&lt;p&gt;Today that is no longer the case. The ecosystem of programming languages is much more diverse (and stronger for it). We have Rust. We have Scala. We also have Go, Python, and JavaScript. There is also Crystal, Elixir, Elm, and Nim (Oh, and Flix of course!) We are in a period of fragmentation. After a decade of object-oriented ossification we are entering a new and exciting period!&lt;&#x2F;p&gt;
&lt;p&gt;If history repeats itself then at some point we will enter a new period of consolidation. It is too early to speculate on which programming languages will be the winners, but I feel confident that they will be much better than C, C++, C#, and Java! (Ok, maybe C++30 will be one of them – that language changes as much as Haskell!)&lt;&#x2F;p&gt;
&lt;p&gt;(Addendum: That said, it is true that many hobby programming languages look the same. But there is a reason for that: if you want to learn about compilers it makes sense to start by implementing a minimal functional or object-oriented programming language.)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;new-programming-languages-are-too-complicated&quot;&gt;New programming languages are too complicated!&lt;&#x2F;h3&gt;
&lt;p&gt;That&#x27;s the way of the world.&lt;&#x2F;p&gt;
&lt;p&gt;What do you think an airline pilot from the 1950&#x27;s would say if he or she entered the flight deck of an Airbus A350? Sure, the principles of flying are the same, and indeed iteration and recursion are not going anywhere. But we cannot expect everything to stay the same. All those instruments are there for a reason and they make flying safer and more efficient.&lt;&#x2F;p&gt;
&lt;p&gt;As another example, once universities start teaching Rust (and we will!) then programming with ownership and lifetimes will become commonplace. As yet another example, today every programmer can reasonably be expected to know about &lt;code&gt;filter&lt;&#x2F;code&gt; and &lt;code&gt;map&lt;&#x2F;code&gt;, but that was certainly not the case 15 years ago!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-programming-language-cannot-be-successful-unless-a-major-tech-company-is-behind-it&quot;&gt;A programming language cannot be successful unless a major tech company is behind it&lt;&#x2F;h3&gt;
&lt;p&gt;Historically that has not been true. Neither PHP, Python, Ruby, Rust, or Scala had major tech companies behind them. If industry support came, it came at a later time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ideas-for-better-communication&quot;&gt;Ideas for Better Communication&lt;&#x2F;h2&gt;
&lt;p&gt;With these points in mind, I want to suggest some ways to improve communication between aspiring programming language designers and software developers:&lt;&#x2F;p&gt;
&lt;p&gt;When presenting a new programming language (or ideas related to a new language):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scope:&lt;&#x2F;strong&gt; State the intended scope of the project. Is it a hobby project made for fun? Is it an open source project hoping to gain traction? Is it a research prototype? Is it a commercially backed project? What is the intended use case? Is there a &quot;killer-app&quot;?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation:&lt;&#x2F;strong&gt; What has been implemented? A compiler? An interpreter? Do you have a standard library? How big is it? How many lines is the project?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Novelty:&lt;&#x2F;strong&gt; What is new in the programming language? Are there some new takes on old ideas? Is there something novel? How is the language an improvement compared to existing languages? Does the language make you think in a new way about programming?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;&#x2F;strong&gt; What resources are behind the programming language? Is it a hobby project? An open source project? An academic project? Are you open to collaboration? Do you have backing (from industry or otherwise)?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Feedback:&lt;&#x2F;strong&gt; What kind of feedback are you looking for? What other people think? Suggestions for improvements and related work? Constructive criticism about the design? What it would take for someone to consider using it?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reality Check:&lt;&#x2F;strong&gt; Try to avoid grandiose or unsubstantiated claims: Do your compiler really outperform modern state-of-the-art C compilers? Is your type system really more expressive than Haskell or Idris? Is your language really safer than Ada?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-about-flix&quot;&gt;What about Flix?&lt;&#x2F;h2&gt;
&lt;p&gt;The time has come to nail our colors to the flag:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scope:&lt;&#x2F;strong&gt; We are building a real programming language intended for real-world use. It is an open-source project lead by academic programming language researchers.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation:&lt;&#x2F;strong&gt; The Flix compiler project is ~137,000 lines of code. We have a realistic compiler, a standard library (extensive, but still under development), a Visual Studio Code extension (with auto-complete!), an online playground, online documentation, and several published papers on the novel aspects of the language.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Novelty:&lt;&#x2F;strong&gt; We have a whole page (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flix.dev&#x2F;innovations&#x2F;&quot;&gt;Innovations&lt;&#x2F;a&gt;) that covers this, but briefly: a unique combination of features, combined with first-class Datalog constraints and a polymorphic effect system.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;&#x2F;strong&gt; We are a group of programming language researchers from Aarhus University and the University of Waterloo together with a small community of open source contributors. Through our research we have funding for working on Flix.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Feedback:&lt;&#x2F;strong&gt; We want to know what people think about Flix, how we can make Flix better, and what it would take for someone to consider using it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reality Check:&lt;&#x2F;strong&gt; We aim to under-promise and over-deliver. We do not promote features before they exist. Our typical pipeline is: (Research) Idea → Implementation → Documentation → Presentation to the World. Development is not secret; everything is on GitHub. We just don&#x27;t promote anything before it is ready. We have exciting things in the pipeline, but you will have to wait a bit before learning about them (or spoil yourself by diving into the GitHub issues!)&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Until next time, happy hacking.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Taming Impurity with Polymorphic Effects</title>
          <pubDate>Fri, 01 May 2020 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/taming-impurity-with-polymorphic-effects/</link>
          <guid>https://blog.flix.dev/blog/taming-impurity-with-polymorphic-effects/</guid>
          <description xml:base="https://blog.flix.dev/blog/taming-impurity-with-polymorphic-effects/">&lt;p&gt;In the blog post &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.digitalmars.com&#x2F;articles&#x2F;b60.html&quot;&gt;Patterns of Bugs&lt;&#x2F;a&gt;, Walter Bright,
the author of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dlang.org&#x2F;&quot;&gt;D programming Language&lt;&#x2F;a&gt;, writes about his
experience working at Boeing and their attitude towards failure:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;[...] The best people have bad days and make mistakes, so the solution is to
change the process so the mistakes cannot happen or cannot propagate.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&quot;One simple example is an assembly that is bolted onto the frame with four bolts. The
obvious bolt pattern is a rectangle. Unfortunately, a rectangle pattern can be assembled
in two different ways, one of which is wrong. The solution is to offset one of the bolt
holes — then the assembly can only be bolted on in one orientation. The possible
mechanic&#x27;s mistake is designed out of the system.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&quot;[...] &lt;em&gt;Parts can only be assembled one way, the correct
way.&lt;&#x2F;em&gt;&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;(Emphasis mine).&lt;&#x2F;p&gt;
&lt;p&gt;Bright continues to explain that these ideas are equally applicable to software: We should
build software such that it can only be assembled correctly. In this blog post, I will
discuss how this idea can be applied to the design of a type and effect system. In
particular, I will show how the Flix programming language and, by extension, its standard
library ensure that pure and impure functions are not assembled incorrectly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;impure-functional-programming&quot;&gt;Impure Functional Programming&lt;&#x2F;h2&gt;
&lt;p&gt;A major selling point of functional programming is that it supports &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.haskell.org&#x2F;Equational_reasoning_examples&quot;&gt;equational reasoning&lt;&#x2F;a&gt;.
Informally, equational reasoning means that we can reason about programs by replacing an
expression by another one, provided they&#x27;re both equal. For example, we can substitute
variables with the expressions they are bound to.&lt;&#x2F;p&gt;
&lt;p&gt;For example, if we have the program fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;let x = 1 + 2;
    (x, x)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can substitute for &lt;code&gt;x&lt;&#x2F;code&gt; and understand this program as:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;(1 + 2, 1 + 2)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately, in the presence of side-effects, such reasoning breaks down.&lt;&#x2F;p&gt;
&lt;p&gt;For example, the program fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;let x = Console.printLine(&amp;quot;Hello World&amp;quot;);
    (x, x)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;is &lt;em&gt;not&lt;&#x2F;em&gt; equivalent to the program:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;(Console.printLine(&amp;quot;Hello World&amp;quot;), Console.printLine(&amp;quot;Hello World&amp;quot;))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Most contemporary functional programming languages, including Clojure, OCaml, and Scala,
forgo equational reasoning by allow arbitrary side-effects inside functions. To be clear,
it is still common to write purely functional programs in these languages and to reason
about them using equational reasoning. The major concern is that there is no language
support to guarantee when such reasoning is valid. Haskell is the only major programming
language that guarantees equational reasoning at the cost of a total and absolute ban on
side-effects.&lt;&#x2F;p&gt;
&lt;p&gt;Flix aims to walk on the middle of the road: We want to support equational reasoning with
strong guarantees while still allowing side-effects. Our solution is a type and effect
system that cleanly separates pure and impure code. The idea of using an effect system
to separate pure and impure code is old, but our implementation, which supports type
inference and polymorphism, is new.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pure-and-impure-functions&quot;&gt;Pure and Impure Functions&lt;&#x2F;h2&gt;
&lt;p&gt;Flix functions are pure by default. We can write a pure function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def inc(x: Int): Int = x + 1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we want to be explicit, but non-idiomatic, we can write:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def inc(x: Int): Int \ {} = x + 1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;code&gt;\ {}&lt;&#x2F;code&gt; specifies that the &lt;code&gt;inc&lt;&#x2F;code&gt; function is pure.&lt;&#x2F;p&gt;
&lt;p&gt;We can also write an impure function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def sayHello(): Unit \ IO = Console.printLine(&amp;quot;Hello World!&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;code&gt;\ IO&lt;&#x2F;code&gt; specifies that the &lt;code&gt;sayHello&lt;&#x2F;code&gt; function is impure.&lt;&#x2F;p&gt;
&lt;p&gt;The Flix type and effect system is &lt;em&gt;sound&lt;&#x2F;em&gt;, hence if we forget the &lt;code&gt;\ IO&lt;&#x2F;code&gt; annotation
on the &lt;code&gt;sayHello&lt;&#x2F;code&gt; function, the compiler will emit a type (or rather effect) error.&lt;&#x2F;p&gt;
&lt;p&gt;The type and effect system cleanly separates pure and impure code. If an expression is pure
then it always evaluates to the same value and it cannot have side-effects. This is part
of what makes Flix functional-first: We can trust that pure functions behave like
mathematical functions.&lt;&#x2F;p&gt;
&lt;p&gt;We have already seen that printing to the screen is impure. Other sources of impurity are
mutation of memory (e.g. writing to main memory, writing to the disk, writing to the
network, etc.). Reading from mutable memory is also impure because there is no guarantee
that we will get the same value if we read the same location twice.&lt;&#x2F;p&gt;
&lt;p&gt;In Flix, the following operations are impure:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Any use of channels (creating, sending, receiving, or selecting).&lt;&#x2F;li&gt;
&lt;li&gt;Any use of references (creating, accessing, or updating).&lt;&#x2F;li&gt;
&lt;li&gt;Any use of arrays (creating, accessing, updating, or slicing).&lt;&#x2F;li&gt;
&lt;li&gt;Any interaction with the Java world.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;higher-order-functions&quot;&gt;Higher-Order Functions&lt;&#x2F;h2&gt;
&lt;p&gt;We can use the type and effect system to restrict the purity (or impurity) of function
arguments that are passed to higher-order functions. This is useful for at least two
reasons: (i) it prevents leaky abstractions where the caller can observe implementation
details of the callee, and (ii) it can help avoid bugs in the sense of Walter Bright&#x27;s
&quot;Parts can only be assembled one way, the correct way.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;We will now look at several examples of how type signatures can control purity or impurity.&lt;&#x2F;p&gt;
&lt;p&gt;We can enforce that the predicate &lt;code&gt;f&lt;&#x2F;code&gt; passed
to &lt;code&gt;Set.exists&lt;&#x2F;code&gt; is &lt;em&gt;pure&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def exists(f: a -&amp;gt; Bool, xs: Set[a]): Bool = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The signature &lt;code&gt;f: a -&amp;gt; Bool&lt;&#x2F;code&gt; denotes a pure function
from &lt;code&gt;a&lt;&#x2F;code&gt; to &lt;code&gt;Bool&lt;&#x2F;code&gt;. Passing an impure function
to &lt;code&gt;exists&lt;&#x2F;code&gt; is a compile-time type error. We want to enforce
that &lt;code&gt;f&lt;&#x2F;code&gt; is pure because the contract for &lt;code&gt;exists&lt;&#x2F;code&gt; makes no guarantees
about how &lt;code&gt;f&lt;&#x2F;code&gt; is called. The implementation of &lt;code&gt;exists&lt;&#x2F;code&gt; may
call &lt;code&gt;f&lt;&#x2F;code&gt; on the elements in &lt;code&gt;xs&lt;&#x2F;code&gt; in any order and any number of times.
This requirement is &lt;em&gt;beneficial&lt;&#x2F;em&gt; because its allows freedom in the implementation
of &lt;code&gt;Set&lt;&#x2F;code&gt;, including in the choice of the underlying data structure and in the
implementation of its operations. For example, we can implement sets using search trees or
with hash tables, and we can perform existential queries in parallel using
fork-join. If &lt;code&gt;f&lt;&#x2F;code&gt; was impure such implementation details would leak and be
observable by the client. &lt;em&gt;Functions can only be assembled one way, the correct way.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can enforce that the function &lt;code&gt;f&lt;&#x2F;code&gt; passed to the
function &lt;code&gt;List.foreach&lt;&#x2F;code&gt; is &lt;em&gt;impure&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def foreach(f: a -&amp;gt; Unit \ IO, xs: List[a]): Unit \ IO = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The signature &lt;code&gt;f: a -&amp;gt; Unit \ IO&lt;&#x2F;code&gt; denotes an impure function
from &lt;code&gt;a&lt;&#x2F;code&gt; to &lt;code&gt;Unit&lt;&#x2F;code&gt;. Passing a pure function to &lt;code&gt;foreach&lt;&#x2F;code&gt; is
a compile-time type error. Given that &lt;code&gt;f&lt;&#x2F;code&gt; is impure and &lt;code&gt;f&lt;&#x2F;code&gt; is called
within &lt;code&gt;foreach&lt;&#x2F;code&gt;, it is itself impure. We enforce that
the &lt;code&gt;f&lt;&#x2F;code&gt; function is impure because it is pointless to apply
a &lt;em&gt;pure&lt;&#x2F;em&gt; function with a &lt;code&gt;Unit&lt;&#x2F;code&gt; return type to every element of a list. &lt;em&gt;Functions
can only be assembled one way, the correct way.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can enforce that event listeners are impure:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def onMouseDn(f: MouseEvent -&amp;gt; Unit \ IO): Unit \ IO = ...
def onMouseUp(f: MouseEvent -&amp;gt; Unit \ IO): Unit \ IO = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Event listeners are always executed for their side-effect: it would be pointless to register
a pure function as an event listener.&lt;&#x2F;p&gt;
&lt;p&gt;We can enforce that assertion and logging facilities are given pure functions:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def assert(f: Unit -&amp;gt; Bool): Unit = ...
def log(f: Unit -&amp;gt; String , l: LogLevel): Unit = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We want to support assertions and log statements that can be enabled and disabled at
run-time. For efficiency, it is critical that when assertions or logging is disabled, we do
not perform any computations that are redundant. We can achieve this by having the assert
and log functions take callbacks that are only invoked when required. A critical property of
these functions is that they must not influence the execution of the program. Otherwise, we
risk situations where enabling or disabling assertions or logging may impact the presence or
absence of a buggy execution. We can prevent such situations by requiring that the functions
passed to &lt;code&gt;assert&lt;&#x2F;code&gt; and &lt;code&gt;log&lt;&#x2F;code&gt; are pure.&lt;&#x2F;p&gt;
&lt;p&gt;We can enforce that user-defined equality functions are pure. We want purity because the
programmer should not make any assumptions about how such functions are used. Moreover, most
collections (e.g. sets and maps) require that equality does not change over time to maintain
internal data structure invariants. Similar considerations apply to hash and comparator
functions.&lt;&#x2F;p&gt;
&lt;p&gt;In the same spirit, we can enforce that one-shot comparator functions are pure:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def minBy(f: a -&amp;gt; b, l: List[a]): Option[a] = ...
def maxBy(f: a -&amp;gt; b, l: List[a]): Option[a] = ...
def sortBy(f: a -&amp;gt; Int32, l: List[a]): List[a] = ...
def groupBy(f: a -&amp;gt; k, l: List[a]): Map[k, List[a]] = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can enforce that the &lt;code&gt;next&lt;&#x2F;code&gt; function passed
to &lt;code&gt;List.unfoldWithIter&lt;&#x2F;code&gt; is impure:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def unfoldWithIter(next: Unit -&amp;gt; Option[a] \ IO): List[a] \ IO
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The unfoldWithIter function is a variant of the &lt;code&gt;unfoldWith&lt;&#x2F;code&gt; function where each
invocation of &lt;code&gt;next&lt;&#x2F;code&gt; changes some mutable state until the unfold completes. For
example, &lt;code&gt;unfoldWithIter&lt;&#x2F;code&gt; is frequently used to convert Java-style iterators into
lists. We want to enforce that &lt;code&gt;next&lt;&#x2F;code&gt; is impure because otherwise it is pointless
to use &lt;code&gt;unfoldWithIter&lt;&#x2F;code&gt;. If &lt;code&gt;next&lt;&#x2F;code&gt; is pure then it must always either
(i) return &lt;code&gt;None&lt;&#x2F;code&gt; which results in the empty list or (ii)
return &lt;code&gt;Some(v)&lt;&#x2F;code&gt; for a value &lt;code&gt;v&lt;&#x2F;code&gt; which would result in an infinite
execution.&lt;&#x2F;p&gt;
&lt;p&gt;We can use purity to reject useless statement expressions. For example, the program:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def main(): Int =
    List.map(x -&amp;gt; x + 1, 1 :: 2 :: Nil);
    123
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;is rejected with the compiler error:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;-- Redundancy Error ------------------ foo.flix

&amp;gt;&amp;gt; Useless expression: It has no side-effect(s) and its result is discarded.

   2 | List.map(x -&amp;gt; x + 1, 1 :: 2 :: Nil);
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       useless expression.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that the &lt;code&gt;List.map(...)&lt;&#x2F;code&gt; expression is pure because the function &lt;code&gt;x  -&amp;gt; x + 1&lt;&#x2F;code&gt; is pure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polymorphic-effects&quot;&gt;Polymorphic Effects&lt;&#x2F;h2&gt;
&lt;p&gt;Flix supports effect polymorphism which means that the effect of a higher-order function can
depend on the effects of its function arguments.&lt;&#x2F;p&gt;
&lt;p&gt;For example, here is the type signature of &lt;code&gt;List.map&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def map(f: a -&amp;gt; b \ ef, xs: List[a]): List[b] \ ef = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The syntax &lt;code&gt;f: a -&amp;gt; b \ ef&lt;&#x2F;code&gt; denotes a function
from &lt;code&gt;a&lt;&#x2F;code&gt; to &lt;code&gt;b&lt;&#x2F;code&gt; with latent effect &lt;code&gt;ef&lt;&#x2F;code&gt;. The signature of
the &lt;code&gt;map&lt;&#x2F;code&gt; function captures that its
effect &lt;code&gt;ef&lt;&#x2F;code&gt; depends on the effect of its argument &lt;code&gt;f&lt;&#x2F;code&gt;.
That is, if &lt;code&gt;map&lt;&#x2F;code&gt; is called with a pure function then its evaluation is pure,
whereas if it is called with an impure function then its evaluation is impure. The effect
signature is &lt;em&gt;conservative&lt;&#x2F;em&gt; (i.e. over-approximate). That is,
the &lt;code&gt;map&lt;&#x2F;code&gt; function is considered impure even in the special case when the list is
empty and its execution is actually pure.&lt;&#x2F;p&gt;
&lt;p&gt;The type and effect system can express combinations of effects using boolean operations.
We can, for example, express that forward function composition &lt;code&gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt; is pure
if both its arguments are pure:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def &amp;gt;&amp;gt;(f: a -&amp;gt; b \ ef1, g: b -&amp;gt; c \ ef2): a -&amp;gt; c \ { ef1, ef2 } = x -&amp;gt; g(f(x))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here the function &lt;code&gt;f&lt;&#x2F;code&gt; has effect &lt;code&gt;ef1&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; has
effect &lt;code&gt;ef2&lt;&#x2F;code&gt;. The returned function has effect &lt;code&gt;ef1 and ef2&lt;&#x2F;code&gt;, i.e. for it
to be pure both &lt;code&gt;ef1&lt;&#x2F;code&gt; and &lt;code&gt;ef2&lt;&#x2F;code&gt; must be pure. Otherwise it is impure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;type-equivalences&quot;&gt;Type Equivalences&lt;&#x2F;h2&gt;
&lt;p&gt;Let us take a short detour.&lt;&#x2F;p&gt;
&lt;p&gt;In a purely functional programming language, such as Haskell, mapping two
functions &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; over a list &lt;code&gt;xs&lt;&#x2F;code&gt; is equivalent to
mapping their composition over the list. That is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;map(f, map(g, xs)) == map(f &amp;gt;&amp;gt; g, xs)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can use such an equation to (automatically) rewrite the program to one that executes more
efficiently because the code on the right only traverses the list once and avoids
allocation of an intermediate list. Haskell already has support for such &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.haskell.org&#x2F;GHC&#x2F;Using_rules&quot;&gt;rewrite rules&lt;&#x2F;a&gt; built into the language.&lt;&#x2F;p&gt;
&lt;p&gt;It would be desirable if we could express the same rewrite rules for programming languages
such as Clojure, OCaml, and Scala. Unfortunately, identities - such as the above - do not
hold in the presence of side-effects. For example, the program:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;let f = x -&amp;gt; {Console.printLine(x); x};
let g = y -&amp;gt; {Console.printLine(y); y};
List.map(f, List.map(g, 1 :: 2 :: Nil))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;prints &lt;code&gt;1, 2, 3, 1, 2, 3&lt;&#x2F;code&gt;. But, if we apply the rewrite rule, the transformed
program now prints &lt;code&gt;1, 1, 2, 2, 3, 3&lt;&#x2F;code&gt;! In the presence of side-effects we cannot
readily apply such rewrite rules.&lt;&#x2F;p&gt;
&lt;p&gt;We can use the Flix type and effect to ensure that a rewrite rule like the above is only
applied when both &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; are pure!&lt;&#x2F;p&gt;
&lt;p&gt;We can, in fact, go even further. If &lt;em&gt;at most
one&lt;&#x2F;em&gt; of &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; is impure then it is still safe to apply
the above rewrite rule. Furthermore, the Flix type and effect system is sufficiently
expressive to capture such a requirement!&lt;&#x2F;p&gt;
&lt;p&gt;We can distill the essence of this point into the type signature:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def mapCompose(f: a -&amp;gt; b \ e1, g: b -&amp;gt; c \ {(not e1) or e2}, xs: List[a]): ... = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is not important exactly what &lt;code&gt;mapCompose&lt;&#x2F;code&gt; does (or even if it makes sense).
What is important is that it has a function signature that requires two function
arguments &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; of which at most one may be impure.&lt;&#x2F;p&gt;
&lt;p&gt;To understand why, let us look closely at the signature of &lt;code&gt;mapCompose&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def mapCompose(f: a -&amp;gt; b \ e1, g: b -&amp;gt; c \ {(not e1) or e2}, xs: List[a]): ... = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;e1 = T&lt;&#x2F;code&gt; (i.e. &lt;code&gt;f&lt;&#x2F;code&gt; is pure) then &lt;code&gt;(not e1) or e2 = F or e2 = e2&lt;&#x2F;code&gt;. In other words, &lt;code&gt;g&lt;&#x2F;code&gt; may be pure or impure. Its purity is not constrained by the type signature.&lt;&#x2F;li&gt;
&lt;li&gt;If, on the other hand, &lt;code&gt;e1 = F&lt;&#x2F;code&gt; (i.e. &lt;code&gt;f&lt;&#x2F;code&gt; is impure) then &lt;code&gt;(not e1) or e2 = T or e2 = T &lt;&#x2F;code&gt;. In other words, &lt;code&gt;g&lt;&#x2F;code&gt; &lt;em&gt;must&lt;&#x2F;em&gt; be pure, otherwise there is a type error.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you think about it, the above is equivalent to the requirement that at most one
of &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; may be impure.&lt;&#x2F;p&gt;
&lt;p&gt;Without going into detail, an interesting aspect of the type and effect system is
that we might as well have given &lt;code&gt;mapCompose&lt;&#x2F;code&gt; the equivalent (equi-most general)
type signature:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def mapCompose(f: a -&amp;gt; b \ {(not e1) or e2}, g: b -&amp;gt; c \ e1, xs: List[a]): ... = ...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where the effects of &lt;code&gt;f&lt;&#x2F;code&gt; and &lt;code&gt;g&lt;&#x2F;code&gt; are swapped.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;benign-impurity&quot;&gt;Benign Impurity&lt;&#x2F;h2&gt;
&lt;p&gt;It is not uncommon for functions to be internally impure but observationally pure.
That is, a function may use mutation and perform side-effects without it being observable
by the external world. We say that such side-effects are &lt;em&gt;benign&lt;&#x2F;em&gt;. Fortunately, we can
still treat such functions as pure with an explicit &lt;em&gt;effect cast&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For example, we can call a Java method (which may have arbitrary side-effects) but
explicitly mark it as pure with an effect cast:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;&#x2F;&#x2F;&#x2F;
&#x2F;&#x2F;&#x2F; Returns the character at position `i` in the string `s`.
&#x2F;&#x2F;&#x2F;
def charAt(i: Int, s: String): Char =
    import java.lang.String.charAt(Int32);
    s.charAt(i) as \ {}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We know that &lt;code&gt;java.lang.String.charAt&lt;&#x2F;code&gt; has is pure hence the cast is safe.&lt;&#x2F;p&gt;
&lt;p&gt;An effect cast, like an ordinary cast, must be used with care. A cast is a mechanism
that allows the programmer to subvert the type (and effect) system. It is the
responsibility of the programmer to ensure that the cast is safe. Unlike type casts, an
effect cast cannot be checked at run-time with the consequence that an unsound effect cast
may silently lead to undefined behavior.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an example of a pure function that is implemented internally using mutation:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;&#x2F;&#x2F;&#x2F;
&#x2F;&#x2F;&#x2F; Strip every indented line in string `s` by `n` spaces. `n` must be greater than `0`.
&#x2F;&#x2F;&#x2F; Note, tabs are counted as a single space.
&#x2F;&#x2F;&#x2F;
&#x2F;&#x2F;&#x2F; [...]
&#x2F;&#x2F;&#x2F;
def stripIndent(n: Int32, s: String): String =
        if (n &amp;lt;= 0 or length(s) == 0)
            s
        else
            stripIndentHelper(n, s) as \ {}
        
&#x2F;&#x2F;&#x2F;
&#x2F;&#x2F;&#x2F; Helper function for `stripIndent`.
&#x2F;&#x2F;&#x2F;
def stripIndentHelper(n: Int32, s: String): String \ IO =
    let sb = StringBuilder.new();
    let limit = Int32.min(n, length(s));
    let step = s1 -&amp;gt; {
        let line = stripIndentDropWhiteSpace(s1, limit, 0);
        StringBuilder.appendLine!(sb, line)
    };
    List.foreach(step, lines(s));
    StringBuilder.toString(sb)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Internally, &lt;code&gt;stripIndentHelper&lt;&#x2F;code&gt; uses a mutable string builder.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;type-inference-and-boolean-unification&quot;&gt;Type Inference and Boolean Unification&lt;&#x2F;h2&gt;
&lt;p&gt;The Flix type and effect system supports inference. Explicit type annotations are never
required locally within a function. As a design choice, we do require type signatures for
top-level definitions. Within a function, the programmer never has to worry about pure and
impure expressions; the compiler automatically infers whether an expression is pure, impure,
or effect polymorphic. The programmer only has to ensure that the declared type and effect
matches the type and effect of the function body.&lt;&#x2F;p&gt;
&lt;p&gt;The details of the type and effect system are the subject of a forthcoming research paper
and will be made available in due time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;The Flix type and effect system separates pure and impure code. The upshot is that a
functional programmer can trust that a pure function behaves like a mathematical function:
it returns the same result when given the same arguments. At the same time, we are still
allowed to write parts of the program in an impure, imperative style. Effect polymorphism
ensures that both pure and impure code can be used with higher-order functions.&lt;&#x2F;p&gt;
&lt;p&gt;We can also use effects to control when higher-order functions require pure (or impure)
functions. We have seen several examples of such use cases, e.g. requiring
that &lt;code&gt;Set.count&lt;&#x2F;code&gt; takes a pure function or
that &lt;code&gt;List.unfoldWithIter&lt;&#x2F;code&gt; takes an impure function. Together, these restrictions
ensure that functions can only be assembled in one way, the correct way.&lt;&#x2F;p&gt;
&lt;p&gt;Until next time, happy hacking.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Naming Functional and Destructive Operations</title>
          <pubDate>Wed, 01 Apr 2020 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/naming-functional-and-destructive-operations/</link>
          <guid>https://blog.flix.dev/blog/naming-functional-and-destructive-operations/</guid>
          <description xml:base="https://blog.flix.dev/blog/naming-functional-and-destructive-operations/">&lt;p&gt;It has been said that there are only two hard problems in computer science: (i) naming, (ii) cache invalidation, and (iii) off-by-one errors. In this blog post, I will explain a &lt;em&gt;name consistency issue&lt;&#x2F;em&gt; that arises when a programming language wants to support both functional and destructive operations. (A functional operation always returns new data, whereas a destructive operation mutates existing data. For example, functionally reversing an array returns a &lt;em&gt;new&lt;&#x2F;em&gt; array with its elements reversed, whereas destructively reversing an array mutates the array in place.)&lt;&#x2F;p&gt;
&lt;p&gt;Flix supports functional, imperative, and logic programming. Flix is intended to be &lt;em&gt;functional-first&lt;&#x2F;em&gt; which simply means that if there is a trade-off between having better functional- or imperative programming support, we tend to favor design choices that support functional programming. For example, the Flix effect system separates pure and impure functions mostly to the benefit of functional programming.&lt;&#x2F;p&gt;
&lt;p&gt;Flix, being imperative, wants to support mutable data structures such as arrays, mutable sets and maps. We have recently added support for all three. But let us for a moment consider a simpler data structure: the humble list.&lt;&#x2F;p&gt;
&lt;p&gt;We can &lt;code&gt;map&lt;&#x2F;code&gt; a function &lt;code&gt;f: a -&amp;gt; b&lt;&#x2F;code&gt; over a list &lt;code&gt;l&lt;&#x2F;code&gt; to obtain a new list of type &lt;code&gt;List[b]&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def map(f: a -&amp;gt; b \ ef, l: List[a]): List[b] \ ef
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(Here the &lt;code&gt;ef&lt;&#x2F;code&gt; denotes that the function is &lt;em&gt;effect polymorphic&lt;&#x2F;em&gt;, but that is for another day.)&lt;&#x2F;p&gt;
&lt;p&gt;We can also &lt;code&gt;map&lt;&#x2F;code&gt; a function over an option:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def map(f: a -&amp;gt; b \ ef, o: Option[a]): Option[b] \ ef
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can also &lt;code&gt;map&lt;&#x2F;code&gt; a function over an array:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def map(f: a -&amp;gt; b \ ef, a: Array[a]): Array[b] \ IO
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is good news: we can program with arrays in a functional-style. Mapping over an array is certainly meaningful and useful. It might even be faster than mapping over a list! Nevertheless, the main reason for having arrays (and mutable sets and maps) is to program with them imperatively. We &lt;em&gt;want&lt;&#x2F;em&gt; to have operations that &lt;em&gt;mutate&lt;&#x2F;em&gt; their data.&lt;&#x2F;p&gt;
&lt;p&gt;We want an operation that applies a function to every element of an array &lt;em&gt;changing it in place&lt;&#x2F;em&gt;. &lt;strong&gt;What should such an operation be called?&lt;&#x2F;strong&gt; We cannot name it &lt;code&gt;map&lt;&#x2F;code&gt; because that name is already taken by the functional version. Let us simply call it &lt;code&gt;mapInPlace&lt;&#x2F;code&gt; for now:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def mapInPlace(f: a -&amp;gt; a \ ef, a: Array[a]): Unit \ IO
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The signature of &lt;code&gt;mapInPlace&lt;&#x2F;code&gt; is different from the signature of &lt;code&gt;map&lt;&#x2F;code&gt; in two important ways:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The function returns &lt;code&gt;Unit&lt;&#x2F;code&gt; instead of returning an array.&lt;&#x2F;li&gt;
&lt;li&gt;The function takes an argument of type &lt;code&gt;a -&amp;gt; a&lt;&#x2F;code&gt; rather than a function of type &lt;code&gt;a -&amp;gt; b&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The latter is required because the type of an array is fixed. An array of bytes cannot be replaced by an array of strings. Consequently, &lt;code&gt;mapInPlace&lt;&#x2F;code&gt; must take a less generic function of type &lt;code&gt;a -&amp;gt; a&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We have seen that it is useful to have both functional and destructive functions such as &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;mapInPlace&lt;&#x2F;code&gt;, but what should such functions be called? Are they sufficiently similar that they should share similar names? What should be the general rule for naming functional operations and their counter-part destructive operations?&lt;&#x2F;p&gt;
&lt;p&gt;To answer these questions, we surveyed the Flix standard library to understand what names are currently being used. The table below shows a small cross section of the results:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Functional Operation&lt;&#x2F;th&gt;&lt;th&gt;Destructive Equivalent&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Array.map&lt;&#x2F;td&gt;&lt;td&gt;Array.mapInPlace&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Array.reverse&lt;&#x2F;td&gt;&lt;td&gt;Array.reverseInPlace&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;missing&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;td&gt;Array.sortByInPlace&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Set.insert&lt;&#x2F;td&gt;&lt;td&gt;not relevant – immutable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Set.union&lt;&#x2F;td&gt;&lt;td&gt;not relevant – immutable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;missing&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;td&gt;MutSet.add&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;missing&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;td&gt;MutSet.addAll&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MutSet.map&lt;&#x2F;td&gt;&lt;td&gt;MutSet.transform&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The table exposes the lack of any established naming convention. Let us consider some of the many inconsistencies: For arrays, the functional and destructive operations are named &lt;code&gt;Array.map&lt;&#x2F;code&gt; and &lt;code&gt;Array.mapInPlace&lt;&#x2F;code&gt;, but for mutable sets the operations are named &lt;code&gt;MutSet.map&lt;&#x2F;code&gt; and &lt;code&gt;MutSet.transform&lt;&#x2F;code&gt;. As another example, for immutable sets, we have &lt;code&gt;Set.insert&lt;&#x2F;code&gt; and &lt;code&gt;Set.union&lt;&#x2F;code&gt;, but these functional operations are missing on the mutable set. Moreover, the mutable version of &lt;code&gt;Set.union&lt;&#x2F;code&gt; is called &lt;code&gt;Set.addAll&lt;&#x2F;code&gt;. Finally, &lt;code&gt;Array.sortByInPlace&lt;&#x2F;code&gt;, what a name!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exploring-the-design-space&quot;&gt;Exploring the Design Space&lt;&#x2F;h2&gt;
&lt;p&gt;With these examples in mind, we tried to come up with a principled approach to naming. Our exploration ended up with the following options:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-i-distinct-names&quot;&gt;Option I: Distinct names&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; We give distinct names to functional and destructive operations. For example, we will have &lt;code&gt;Array.map&lt;&#x2F;code&gt; and &lt;code&gt;Array.transform&lt;&#x2F;code&gt;, and &lt;code&gt;MutSet.union&lt;&#x2F;code&gt; and &lt;code&gt;MutSet.addAll&lt;&#x2F;code&gt;. We reserve the most common names (e.g. &lt;code&gt;map&lt;&#x2F;code&gt;) for the functional operations.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; With distinct names there is little room for confusion, but it may be difficult to come up with meaningful names. For example, what should the destructive version of &lt;code&gt;reverse&lt;&#x2F;code&gt; be called?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-ii-use-similar-names-but-with-a-prefix-or-suffix&quot;&gt;Option II: Use similar names but with a prefix or suffix&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; We reuse names between functional and destructive operations. To distinguish operations, we add a prefix or suffix to the name. For example, &lt;code&gt;reverseInPlace&lt;&#x2F;code&gt;, &lt;code&gt;inPlaceReverse&lt;&#x2F;code&gt;, &lt;code&gt;reverseMut&lt;&#x2F;code&gt;, or similar.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; The advantage of this approach is that names are immediately consistent. The disadvantages are that: (i) it may be difficult to come up with a good prefix or suffix word, (ii) some users may dislike the chosen prefix or suffix, and (iii) it may be confusing that the signatures for two similarly named operations differ not only in the return type, but also in the polymorphism of the arguments.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-iii-use-similar-names-but-with-a-prefix-or-suffix-symbol&quot;&gt;Option III: Use similar names but with a prefix or suffix symbol&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; Similar to the previous proposal, but instead we use a symbol. For example: &lt;code&gt;reverse!&lt;&#x2F;code&gt;, &lt;code&gt;reverse*&lt;&#x2F;code&gt;, or the like.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; The same advantages and disadvantages of the previous proposal, but with the difference that using a symbol may be more or less appealing to programmers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-iv-use-namespaces&quot;&gt;Option IV: Use namespaces&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; We place all functional operations into one namespace and all destructive operations into another. For example, we might have &lt;code&gt;Array.reverse&lt;&#x2F;code&gt; and &lt;code&gt;MutArray.reverse&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; While this solution appears simple, it has two downsides: (i) we now have multiple functions named &lt;code&gt;reverse&lt;&#x2F;code&gt; with different semantics and (ii) we get a plethora of namespaces for data structures that exist in both immutable and mutable variants. For example, we might end up with &lt;code&gt;Set.map&lt;&#x2F;code&gt; (functional map on an immutable set), &lt;code&gt;MutSet.Mut.map&lt;&#x2F;code&gt; (destructive map on a mutable set), and &lt;code&gt;MutSet.Imm.map&lt;&#x2F;code&gt; (functional map on a mutable set).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-v-the-python-approach-sort-vs-sorted&quot;&gt;Option V: The Python approach: sort vs. sorted&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; In Python the &lt;code&gt;sorted&lt;&#x2F;code&gt; operation functionally returns a new sorted list whereas the &lt;code&gt;sort&lt;&#x2F;code&gt; operation destructively sorts a list in place. We use the same scheme for &lt;code&gt;reverse&lt;&#x2F;code&gt; and &lt;code&gt;reversed&lt;&#x2F;code&gt;, &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;mapped&lt;&#x2F;code&gt;, and so forth.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; An internet search reveals that many programmers are puzzled by the Python naming scheme. Another disadvantage is that the common functional names, e.g. &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;reverse&lt;&#x2F;code&gt; would be reserved for destructive operations (unless we adopt the &lt;em&gt;opposite&lt;&#x2F;em&gt; convention of Python).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-vi-drop-functional-operations-for-mutable-data&quot;&gt;Option VI: Drop functional operations for mutable data&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Proposal:&lt;&#x2F;strong&gt; We drop support for functional operations on mutable data structures. If the user wants to map a function over an array, mutable set, or mutable map he or she must first convert it to an immutable data structure. For example, to functionally reverse an array one would write &lt;code&gt;a.toList().reverse().toArray()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Discussion:&lt;&#x2F;strong&gt; The &quot;stick your head in the sand approach&quot;. The programmer must explicitly convert back and forth between immutable and mutable data structures. While such an approach side-steps the naming issue, it is verbose and slow (because we have to copy collections back and forth). Deliberately leaving functionality out of the standard library does not mean that programmers will not miss it; instead we are just passing the problem onto them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-principles&quot;&gt;The Principles&lt;&#x2F;h2&gt;
&lt;p&gt;We debated these options and slept on them for a few nights before we ultimately ended up with the following hybrid principles:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;library-mutable-data-is-functional-data&quot;&gt;Library: Mutable Data is Functional Data&lt;&#x2F;h3&gt;
&lt;p&gt;In Flix, every mutable data structure supports functional operations. For example, mutable collections, such as &lt;code&gt;Array&lt;&#x2F;code&gt; and &lt;code&gt;MutSet&lt;&#x2F;code&gt; support the &lt;code&gt;map&lt;&#x2F;code&gt; operation. Flix, being functional-first, reserves functional names for functional operations. Across the standard library &lt;code&gt;map&lt;&#x2F;code&gt; has the same name and the same type signature.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;library-destructive-operations-are-marked-with&quot;&gt;Library: Destructive Operations are Marked with &#x27;!&#x27;&lt;&#x2F;h3&gt;
&lt;p&gt;In Flix, every destructive operation is suffixed with an exclamation point. For example, &lt;code&gt;Array.reverse(a)&lt;&#x2F;code&gt; returns a new array with the elements of &lt;code&gt;a&lt;&#x2F;code&gt; in reverse order, whereas &lt;code&gt;Array.reverse!(a)&lt;&#x2F;code&gt; destructively re-orders the elements of &lt;code&gt;a&lt;&#x2F;code&gt;. Note: This principle applies to destructive operations that operate on data structures, not to impure functions in general, e.g. &lt;code&gt;Console.printLine&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As a side-note: Scheme has used &lt;code&gt;!&lt;&#x2F;code&gt; to indicate destructive operations for a long-time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;library-consistent-names-of-functional-and-destructive-operations&quot;&gt;Library: Consistent Names of Functional and Destructive Operations&lt;&#x2F;h3&gt;
&lt;p&gt;In Flix, functional and destructive operations that share (i) similar behavior and (ii) similar type signatures share similar names. For example, &lt;code&gt;Array.reverse&lt;&#x2F;code&gt; and &lt;code&gt;Array.reverse!&lt;&#x2F;code&gt; share the same name. On the other hand, &lt;code&gt;Array.transform!&lt;&#x2F;code&gt; is called &lt;code&gt;transform!&lt;&#x2F;code&gt; and not &lt;code&gt;map!&lt;&#x2F;code&gt; because its type signature is dissimilar to map (i.e. map works on functions of type &lt;code&gt;a -&amp;gt; b&lt;&#x2F;code&gt;, but transform requires functions of type &lt;code&gt;a -&amp;gt; a&lt;&#x2F;code&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;We are in the process of refactoring the standard library to satisfy these new principles.&lt;&#x2F;p&gt;
&lt;p&gt;Going forward, we are sensitive to at least four potential issues:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Whether users come to like the aesthetics of names that end in exclamation point.&lt;&#x2F;li&gt;
&lt;li&gt;If there is confusion about when exclamation points should be part of a name.&lt;&#x2F;li&gt;
&lt;li&gt;If there is confusion about when two operations should share the same name.&lt;&#x2F;li&gt;
&lt;li&gt;That Rust uses exclamation points for macro applications.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As Flix continues to mature, we will keep an eye on these issues.&lt;&#x2F;p&gt;
&lt;p&gt;Until next time, happy hacking.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Redundancies as Compile-Time Errors</title>
          <pubDate>Sat, 01 Feb 2020 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/redundancies-as-compile-time-errors/</link>
          <guid>https://blog.flix.dev/blog/redundancies-as-compile-time-errors/</guid>
          <description xml:base="https://blog.flix.dev/blog/redundancies-as-compile-time-errors/">&lt;p&gt;As software developers, we strive to write correct and maintainable code. Today, I want to share some code where I failed in these two goals.&lt;&#x2F;p&gt;
&lt;p&gt;I will show you real-world code from the Flix compiler and ask you to determine what is wrong with the code. Then, later, I will argue how programming languages can help avoid the type of problems you will see. (Note to the reader: The Flix compiler is (currently) written in Scala, so the code is in Scala, but the lessons learned are applied to the Flix programming language. I hope that makes sense.)&lt;&#x2F;p&gt;
&lt;p&gt;Let us begin our journey by looking at the following code fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;scala&quot;&gt;case Expression.ApplyClo(exp, args, tpe, loc) =&amp;gt;
    val e = visitExp(exp)
    val as = args map visitExp
    Expression.ApplyClo(e, as, tpe, loc)

case Expression.ApplyDef(sym, args, tpe, loc) =&amp;gt;
    val as = args map visitExp
    Expression.ApplyDef(sym, as, tpe, loc)

case Expression.Unary(op, exp, tpe, loc) =&amp;gt;
    val e = visitExp(exp)
    Expression.Unary(op, exp, tpe, loc)

case Expression.Binary(op, exp1, exp2, tpe, loc) =&amp;gt;
    val e1 = visitExp(exp1)
    val e2 = visitExp(exp2)
    Expression.Binary(op, e1, e2, tpe, loc)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do you see any issues?&lt;&#x2F;p&gt;
&lt;p&gt;If not, look again.&lt;&#x2F;p&gt;
&lt;p&gt;Ok, got it?&lt;&#x2F;p&gt;
&lt;p&gt;The code has a subtle bug: In the case for &lt;code&gt;Unary&lt;&#x2F;code&gt; the local variable &lt;code&gt;e&lt;&#x2F;code&gt; holds the result of the recursion on &lt;code&gt;exp&lt;&#x2F;code&gt;. But by mistake the reconstruction of &lt;code&gt;Unary&lt;&#x2F;code&gt; uses &lt;code&gt;exp&lt;&#x2F;code&gt; and not &lt;code&gt;e&lt;&#x2F;code&gt; as intended. The local variable &lt;code&gt;e&lt;&#x2F;code&gt; is unused. Consequently, the specific transformations applied by &lt;code&gt;visitExp&lt;&#x2F;code&gt; under unary expressions are silently discarded. This bug was in the Flix compiler for some time before it was discovered.&lt;&#x2F;p&gt;
&lt;p&gt;Let us continue our journey with the following code fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;scala&quot;&gt;case ResolvedAst.Expression.IfThenElse(exp1, exp2, exp3, tvar, evar, loc) =&amp;gt;
    for {
        (tpe1, eff1) &amp;lt;- visitExp(exp1)
        (tpe2, eff2) &amp;lt;- visitExp(exp2)
        (tpe3, eff3) &amp;lt;- visitExp(exp3)
        condType &amp;lt;- unifyTypM(mkBoolType(), tpe1, loc)
        resultTyp &amp;lt;- unifyTypM(tvar, tpe2, tpe3, loc)
        resultEff &amp;lt;- unifyEffM(evar, eff1, eff2, loc)
    } yield (resultTyp, resultEff)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do you see any issues?&lt;&#x2F;p&gt;
&lt;p&gt;If not, look again.&lt;&#x2F;p&gt;
&lt;p&gt;Ok, got it?&lt;&#x2F;p&gt;
&lt;p&gt;The code has a similar bug: The local variable &lt;code&gt;eff3&lt;&#x2F;code&gt; is not used, but it should have been used to compute &lt;code&gt;resultEff&lt;&#x2F;code&gt;. While this bug never made it into any release of Flix, it did cause a lot of head-scratching.&lt;&#x2F;p&gt;
&lt;p&gt;Now we are getting the hang of things! What about this code fragment?:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;scala&quot;&gt;&#x2F;**
  * Returns the disjunction of the two effects `eff1` and `eff2`.
  *&#x2F;
def mkOr(ef1f: Type, eff2: Type): Type = eff1 match {
    case Type.Cst(TypeConstructor.Pure) =&amp;gt; Pure
    case Type.Cst(TypeConstructor.Impure) =&amp;gt; eff2
    case _ =&amp;gt; eff2 match {
        case Type.Cst(TypeConstructor.Pure) =&amp;gt; Pure
        case Type.Cst(TypeConstructor.Impure) =&amp;gt; eff1
        case _ =&amp;gt; Type.Apply(Type.Apply(Type.Cst(TypeConstructor.Or), eff1), eff2)
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do you see any issues?&lt;&#x2F;p&gt;
&lt;p&gt;I am sure you did.&lt;&#x2F;p&gt;
&lt;p&gt;The bug is the following: The formal parameter to &lt;code&gt;mkOr&lt;&#x2F;code&gt; is misspelled &lt;code&gt;ef1f&lt;&#x2F;code&gt; instead of &lt;code&gt;eff1&lt;&#x2F;code&gt;. But how does this even compile, you ask? Well, unfortunately the &lt;code&gt;mkOr&lt;&#x2F;code&gt; function is nested inside another function that just so happens to have an argument also named &lt;code&gt;eff1&lt;&#x2F;code&gt;! Damn Murphy and his laws. The intention was for the formal parameters of &lt;code&gt;mkOr&lt;&#x2F;code&gt; to shadow &lt;code&gt;eff1&lt;&#x2F;code&gt; (and &lt;code&gt;eff2&lt;&#x2F;code&gt;), but because of the misspelling, &lt;code&gt;ef1f&lt;&#x2F;code&gt; ended up as unused and &lt;code&gt;eff1&lt;&#x2F;code&gt; (a completely unrelated variable) was used instead. The issue was found during development, but not before several hours of wasted work. Not that I am bitter or anything...&lt;&#x2F;p&gt;
&lt;p&gt;We are almost at the end of our journey! But what about this beast:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;scala&quot;&gt;&#x2F;**
 * Returns the result of looking up the given `field` on the given `klass`.
 *&#x2F;
def lookupNativeField(klass: String, field: String, loc: Location): ... = try {
    &#x2F;&#x2F; retrieve class object.
    val clazz = Class.forName(klass)
    
    &#x2F;&#x2F; retrieve the matching static fields.
    val fields = clazz.getDeclaredFields.toList.filter {
        case field =&amp;gt; field.getName == field &amp;amp;&amp;amp; 
                      Modifier.isStatic(field.getModifiers)
    }
    
    &#x2F;&#x2F; match on the number of fields.
    fields.size match {
        case 0 =&amp;gt; Err(NameError.UndefinedNativeField(klass, field, loc))
        case 1 =&amp;gt; Ok(fields.head)
        case _ =&amp;gt; throw InternalCompilerException(&amp;quot;Ambiguous native field?&amp;quot;)
    }
} catch {
    case ex: ClassNotFoundException =&amp;gt; 
        Err(NameError.UndefinedNativeClass(klass, loc))
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do you see any issues?&lt;&#x2F;p&gt;
&lt;p&gt;If not, look again.&lt;&#x2F;p&gt;
&lt;p&gt;Ok, got it?&lt;&#x2F;p&gt;
&lt;p&gt;Still nothing?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Pause for dramatic effect.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Morpheus: What if I told you...&lt;&#x2F;p&gt;
&lt;p&gt;Morpheus: ... that the function has been maintained over a long period of time...&lt;&#x2F;p&gt;
&lt;p&gt;Morpheus: &lt;em&gt;But that there is no place where the function is called!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I am sorry if that was unfair. But was it really? The Flix code base is more than 100,000 lines of code, so it is hard to imagine that a single person can hold it in his or her head.&lt;&#x2F;p&gt;
&lt;p&gt;As these examples demonstrate, and as has been demonstrated in the research literature (see e.g. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.stanford.edu&#x2F;~engler&#x2F;p401-xie.pdf&quot;&gt;Xie and Engler 2002&lt;&#x2F;a&gt;), redundant or unused code is often buggy code.&lt;&#x2F;p&gt;
&lt;p&gt;To overcome such issues, Flix is very strict about redundant and unused code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flix-treats-unused-code-as-compile-time-errors&quot;&gt;Flix Treats Unused Code as Compile-Time Errors&lt;&#x2F;h2&gt;
&lt;p&gt;The Flix compiler emits a &lt;em&gt;compile-time error&lt;&#x2F;em&gt; for the following redundancies:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Type&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Def&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A function is declared, but never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Enum&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;An enum type is declared, but never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Enum Case&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A case (variant) of an enum is declared, but never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Formal Parameter&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A formal parameter is declared, but never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Type Parameter&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A function or enum declares a type parameter, but it is never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unused Local Variable&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A function declares a local variable, but it is never used.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Shadowed Local Variable&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A local variable hides another local variable.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Unconditional Recursion&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;A function unconditionally recurses on all control-flow paths.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Useless Expression Statement&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;An expression statement discards the result of a pure expression.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;As the Flix language grows, we will continue to expand the list.&lt;&#x2F;p&gt;
&lt;p&gt;Let us look at three concrete examples of such compile-time errors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-i-unused-local-variable&quot;&gt;Example I: Unused Local Variable&lt;&#x2F;h2&gt;
&lt;p&gt;Given the program fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def main(): Bool =
    let l1 = List.range(0, 10);
    let l2 = List.intersperse(42, l1);
    let l3 = List.range(0, 10);
    let l4 = List.map(x -&amp;gt; x :: x :: Nil, l2);
    let l5 = List.flatten(l4);
    List.exists(x -&amp;gt; x == 0, l5)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Flix compiler emits the compile-time error:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;-- Redundancy Error -------------------------------------------------- foo.flix

&amp;gt;&amp;gt; Unused local variable &amp;#39;l3&amp;#39;. The variable is not referenced within its scope.

4 |     let l3 = List.range(0, 10);
            ^^
            unused local variable.


Possible fixes:

  (1)  Use the local variable.
  (2)  Remove local variable declaration.
  (3)  Prefix the variable name with an underscore.


Compilation failed with 1 error(s).
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error message offers suggestions for how to fix the problem or alternatively how to make the compiler shut up (by explicitly marking the variable as unused).&lt;&#x2F;p&gt;
&lt;p&gt;Modern programming languages like Elm and Rust offer a similar feature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-ii-unused-enum-case&quot;&gt;Example II: Unused Enum Case&lt;&#x2F;h2&gt;
&lt;p&gt;Given the enum declaration:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;enum Color {
    case Red,
    case Green,
    case Blue
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If only &lt;code&gt;Red&lt;&#x2F;code&gt; and &lt;code&gt;Green&lt;&#x2F;code&gt; are used then we get the Flix compile-time error:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;-- Redundancy Error -------------------------------------------------- foo.flix

&amp;gt;&amp;gt; Unused case &amp;#39;Blue&amp;#39; in enum &amp;#39;Color&amp;#39;.

4 |     case Blue
             ^^^^
             unused tag.

Possible fixes:

  (1)  Use the case.
  (2)  Remove the case.
  (3)  Prefix the case with an underscore.

Compilation failed with 1 error(s).
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, programming languages like Elm and Rust offer a similar feature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-iii-useless-expression-statement&quot;&gt;Example III: Useless Expression Statement&lt;&#x2F;h2&gt;
&lt;p&gt;Given the program fragment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def main(): Int =
    List.map(x -&amp;gt; x + 1, 1 :: 2 :: Nil);
    123
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Flix compiler emits the compile-time error:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;-- Redundancy Error -------------------------------------------------- foo.flix

&amp;gt;&amp;gt; Useless expression: It has no side-effect(s) and its result is discarded.

2 |     List.map(x -&amp;gt; x + 1, 1 :: 2 :: Nil);
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        useless expression.


Possible fixes:

  (1)  Use the result computed by the expression.
  (2)  Remove the expression statement.
  (3)  Introduce a let-binding with a wildcard name.

Compilation failed with 1 error(s).
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with the code is that the evaluation of &lt;code&gt;List.map(x -&amp;gt; x + 1, 1 :: 2 :: Nil)&lt;&#x2F;code&gt; has no side-effect(s) and its result is discarded.&lt;&#x2F;p&gt;
&lt;p&gt;Another classic instance of this problem is when someone calls e.g. &lt;code&gt;checkPermission(...)&lt;&#x2F;code&gt; and expects it to throw an exception if the user has insufficient permissions, but in fact, the function simply returns a boolean which is then discarded.&lt;&#x2F;p&gt;
&lt;p&gt;But this is &lt;em&gt;not&lt;&#x2F;em&gt; your Grandma&#x27;s average compile-time error. At the time of writing, I know of no other programming language that offers a similar warning or error with the same precision as Flix. If you do, please drop me a line on Gitter. (Before someone rushes to suggest &lt;code&gt;must_use&lt;&#x2F;code&gt; and friends, please consider whether they work in the presence of polymorphism as outlined below).&lt;&#x2F;p&gt;
&lt;p&gt;The key challenge is to (automatically) determine whether an expression is pure (side-effect free) in the presence of polymorphism. Specifically, the call to &lt;code&gt;List.map&lt;&#x2F;code&gt; is pure because the &lt;em&gt;function argument&lt;&#x2F;em&gt; &lt;code&gt;x -&amp;gt; x + 1&lt;&#x2F;code&gt; is pure. In other words, the purity of &lt;code&gt;List.map&lt;&#x2F;code&gt; depends on the purity of its argument: it is &lt;em&gt;effect polymorphic&lt;&#x2F;em&gt;. The combination of type inference, fine-grained effect inference, and effect polymorphism is a strong cocktail that I plan to cover in a future blog post.&lt;&#x2F;p&gt;
&lt;p&gt;Note: The above is fully implemented in master, but has not yet been &quot;released&quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;I hope that I have convinced you that unused code is a threat to correct and maintainable code. However, it is a threat that can be neutralized by better programming language design and with minor changes to development practices. Moreover, I believe that a compiler that reports redundant or unused code can help programmers – whether inexperienced or seasoned – avoid stupid mistakes that waste time during development.&lt;&#x2F;p&gt;
&lt;p&gt;A reasonable concern is whether working with a compiler that rejects programs with unused code is too cumbersome or annoying. In my experience, the answer is no. After a small learning period, whenever you want to introduce a new code fragment that will not immediately be used, you simple remember to prefix it with an underscore, and then later you come back and remove the underscore when you are ready to use it.&lt;&#x2F;p&gt;
&lt;p&gt;While there might be a short adjustment period, the upside is &lt;em&gt;huge&lt;&#x2F;em&gt;: The compiler provides an iron-clad guarantee that all my code is used. Moreover, whenever I refactor some code, I am immediately informed if some code fragment becomes unused. I think such long-term maintainability concerns are significantly more important than a little bit of extra work during initial development.&lt;&#x2F;p&gt;
&lt;p&gt;Until next time, happy hacking.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Design Flaws in Flix</title>
          <pubDate>Wed, 01 Jan 2020 00:00:00 +0000</pubDate>
          <author>Magnus Madsen</author>
          <link>https://blog.flix.dev/blog/design-flaws-in-flix/</link>
          <guid>https://blog.flix.dev/blog/design-flaws-in-flix/</guid>
          <description xml:base="https://blog.flix.dev/blog/design-flaws-in-flix/">&lt;p&gt;Inspired by the blog post &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;futhark-lang.org&#x2F;blog&#x2F;2019-12-18-design-flaws-in-futhark.html&quot;&gt;Design Flaws in Futhark&lt;&#x2F;a&gt;, I decided to take stock and reflect on some of the design flaws that I believe we made during the development of the Flix programming language. I went through old Github issues and pull requests to discover some of the challenging issues that we have been or still are struggling with. I will classify the design flaws into four categories: (i) design flaws that still plague the Flix language, (ii) design flaws that have been fixed, (iii) poor designs that were thankfully never implemented, and finally (iv) design choices where the jury is still out.&lt;&#x2F;p&gt;
&lt;p&gt;I want to emphasize that language design and implementation is a herculean task and that there are features planned for Flix which have not yet been implemented. The lack of a specific feature is not a design flaw, but rather a question of when we can get around to it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-flaws-present-in-flix&quot;&gt;Design Flaws Present in Flix&lt;&#x2F;h2&gt;
&lt;p&gt;The following design flaws are still present in Flix. Hopefully some day they will be fixed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-switch-expression&quot;&gt;The Switch Expression&lt;&#x2F;h3&gt;
&lt;p&gt;Flix supports the &lt;code&gt;switch&lt;&#x2F;code&gt; expression:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;switch {
    case cond1 =&amp;gt; exp1
    case cond2 =&amp;gt; exp2
    case cond3 =&amp;gt; exp3
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where the boolean expressions &lt;code&gt;cond1&lt;&#x2F;code&gt;, &lt;code&gt;cond2&lt;&#x2F;code&gt;, and &lt;code&gt;cond3&lt;&#x2F;code&gt; are evaluated from top to bottom until one of them returns true and then its associated body expression is evaluated. The idea, quite simply, is to have a control-flow structure that visually resembles an ordinary pattern match, but where there is no match value.&lt;&#x2F;p&gt;
&lt;p&gt;In hind-sight, the &lt;code&gt;switch&lt;&#x2F;code&gt; expression is nothing more than a glorified &lt;code&gt;if-then-else-if&lt;&#x2F;code&gt; construct that does not carry its own weight. It is an expenditure on the complexity and strangeness budget that offers almost no gain over using plain &lt;code&gt;if-then-else-if&lt;&#x2F;code&gt;. Moreover, it is error-prone, because it lacks an explicit &lt;code&gt;else&lt;&#x2F;code&gt; branch in case none of the conditions evaluate to true. We plan to remove it in future versions of Flix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;string-concatenation-with-plus&quot;&gt;String Concatenation with Plus&lt;&#x2F;h3&gt;
&lt;p&gt;Like most contemporary languages, Flix uses &lt;code&gt;+&lt;&#x2F;code&gt; for string concatenation. While this is an uncontroversial design choice, it does not make much sense since strings are not commutative, e.g. &lt;code&gt;&quot;abc&quot; + &quot;def&quot;&lt;&#x2F;code&gt; is &lt;em&gt;not&lt;&#x2F;em&gt; the same as &lt;code&gt;&quot;def&quot; + &quot;abc&quot;&lt;&#x2F;code&gt;. A better alternative would be to use &lt;code&gt;++&lt;&#x2F;code&gt; as in Haskell. However, I believe an even better design choice would be to forgo string concatenation and instead rely entirely on string interpolation. String interpolation is a much more powerful and elegant solution to the problem of building complex strings.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-flaws-no-longer-present-in-flix&quot;&gt;Design Flaws No Longer Present in Flix&lt;&#x2F;h2&gt;
&lt;p&gt;The following design flaws have been fixed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;compilation-of-option-to-null&quot;&gt;Compilation of Option to Null&lt;&#x2F;h3&gt;
&lt;p&gt;Flix compiles to JVM bytecode and runs on the virtual machine. An earlier version of Flix had an optimization that would take the &lt;code&gt;Option&lt;&#x2F;code&gt; enum:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;Option[a] {
    case None,
    case Some(a)
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and compile the &lt;code&gt;None&lt;&#x2F;code&gt; value to &lt;code&gt;null&lt;&#x2F;code&gt; and &lt;code&gt;Some(a)&lt;&#x2F;code&gt; to the underlying value of &lt;code&gt;a&lt;&#x2F;code&gt;. The idea was to save allocation and de-allocation of &lt;code&gt;Some&lt;&#x2F;code&gt; values, speeding up evaluation.&lt;&#x2F;p&gt;
&lt;p&gt;But, this screws up interoperability with Java libraries. In Java &lt;code&gt;null&lt;&#x2F;code&gt; might be given a special meaning that is incompatible with the meaning &lt;code&gt;None&lt;&#x2F;code&gt;. For example, certain Java collections cannot contain &lt;code&gt;null&lt;&#x2F;code&gt; and trying to put &lt;code&gt;None&lt;&#x2F;code&gt; into one of these would raise an unexpected exception. Consequently, Flix no longer has this optimization.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;useless-library-functions&quot;&gt;Useless Library Functions&lt;&#x2F;h3&gt;
&lt;p&gt;Flix aims to have a robust standard library that avoids some of the pitfalls of other standard libraries. We have been particularly focused on two aspects: (i) ensuring that functions and types have consistent names, e.g. &lt;code&gt;map&lt;&#x2F;code&gt; is named &lt;code&gt;map&lt;&#x2F;code&gt; for both &lt;code&gt;Option&lt;&#x2F;code&gt; and &lt;code&gt;List&lt;&#x2F;code&gt;, and (ii) to avoid partial functions, such as &lt;code&gt;List.head&lt;&#x2F;code&gt; and &lt;code&gt;List.tail&lt;&#x2F;code&gt; which are not defined for empty lists.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, despite these principles, we still managed to implement some problematic functions in the library. For example, we used to have the functions &lt;code&gt;Option.isNone&lt;&#x2F;code&gt; and &lt;code&gt;Option.isSome&lt;&#x2F;code&gt;. The problem with these functions is that they are not really useful and they lead to brittle code. For example, &lt;em&gt;if&lt;&#x2F;em&gt; &lt;code&gt;Option.isSome&lt;&#x2F;code&gt; returns &lt;code&gt;true&lt;&#x2F;code&gt; then that information cannot be used to unwrap the option anyway. Thus such functions are not really useful.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;function-call-syntax&quot;&gt;Function Call Syntax&lt;&#x2F;h2&gt;
&lt;p&gt;Inspired by Scala, early versions of Flix did not always use parentheses to mark a function call. For example, the function:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def f: Int32 = 21
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;could be called by writing:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def g: Int32 = f + 42 &#x2F;&#x2F; returns 63
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with this design is at least two-fold: (i) it hides when a function is applied, which is terrible in a language with side-effects, and (ii) how does one express the closure of &lt;code&gt;f&lt;&#x2F;code&gt;? (In Scala the answer is to write &lt;code&gt;f _&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Today, in Flix, the code is written as:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def f(): Int32 = 21
def g: Int32 = f() + 42 &#x2F;&#x2F; returns 63
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which makes it clear when there is a function call.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;infix-type-application&quot;&gt;Infix Type Application&lt;&#x2F;h3&gt;
&lt;p&gt;In Flix, a function &lt;code&gt;f&lt;&#x2F;code&gt; can be called with the arguments &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;y&lt;&#x2F;code&gt; in three ways: In standard prefix-style &lt;code&gt;f(x, y)&lt;&#x2F;code&gt;, in infix-style &lt;code&gt;x `f` y&lt;&#x2F;code&gt;, and in postfix-style &lt;code&gt;x.f(y)&lt;&#x2F;code&gt;. The latter is also sometimes referred to as universal function call syntax. I personally feel reasonably confident that all three styles are worth supporting. The postfix-style fits well for function calls such as &lt;code&gt;a.length()&lt;&#x2F;code&gt; where the &lt;code&gt;length&lt;&#x2F;code&gt; function feels closely associated with the receiver argument. The infix-style fits well with user-defined binary operations such as &lt;code&gt;x `lub` y&lt;&#x2F;code&gt; where &lt;code&gt;lub&lt;&#x2F;code&gt; is the least upper bound of &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;y&lt;&#x2F;code&gt;. And of course the prefix-style is the standard way to perform a function call.&lt;&#x2F;p&gt;
&lt;p&gt;Type constructors, such as &lt;code&gt;Option&lt;&#x2F;code&gt; and &lt;code&gt;Result&lt;&#x2F;code&gt; can be thought of a special type of functions. Hence, it makes sense that their syntax should mirror function applications. For example, we can write the type applications &lt;code&gt;Option[Int32]&lt;&#x2F;code&gt; and &lt;code&gt;Result[Int32, Int32]&lt;&#x2F;code&gt; mirroring the prefix style of regular function applications. Similarly, for a while, Flix supported infix and postfix &lt;em&gt;type applications&lt;&#x2F;em&gt;. That is, the former could also be expressed as: &lt;code&gt;Int32.Option[]&lt;&#x2F;code&gt; and &lt;code&gt;Int32.Result[Int32]&lt;&#x2F;code&gt;, or even as &lt;code&gt;Int32 `Result` Int32&lt;&#x2F;code&gt;. Thankfully, those days are gone. Striving for such uniformity in every place does not seem worth it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;unit-tests-that-manually-construct-abstract-syntax-trees&quot;&gt;Unit Tests that Manually Construct Abstract Syntax Trees&lt;&#x2F;h3&gt;
&lt;p&gt;The Flix compiler comes with more than 6,500 manually written unit tests. Each unit test is a Flix function that performs some computation, often with an expected result. The unit tests are expressed in Flix itself. For example:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;@test
def testArrayStore01(): Unit = let x = [1]; x[0] = 42
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In earlier versions of Flix such unit tests were expressed by manually constructing &quot;small&quot; abstract syntax tree fragments. For example, the above test would be expressed as something like:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;Let(Var(&amp;quot;x&amp;quot;, ...), ArrayNew(...), ArrayStore(Var(&amp;quot;x&amp;quot;), Int32(0), Int32(42)))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with such tests is at least two-fold: (i) the tests turn out to be anything but small and (ii) maintenance becomes an absolute nightmare. I found that the surface syntax of Flix has remained relatively stable over time, but the abstract syntax trees have changed frequently, making maintenance of such test cases tedious and time consuming.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bad-ideas-that-were-never-implemented&quot;&gt;Bad Ideas that were Never Implemented&lt;&#x2F;h2&gt;
&lt;p&gt;These ideas were fortunately never implemented in Flix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-itself-keyword&quot;&gt;The Itself Keyword&lt;&#x2F;h3&gt;
&lt;p&gt;The idea was to introduce a special keyword that within a pattern match would refer to the match value. For example:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;def foo(e: Exp): Exp = match e {
    &#x2F;&#x2F; ... many lines ...
    case IfThenElse(e1, e2, e3) =&amp;gt; itself &#x2F;&#x2F; refers to the value of e.
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The keyword &lt;code&gt;itself&lt;&#x2F;code&gt; refers to the value of the match expression, i.e. the value of &lt;code&gt;e&lt;&#x2F;code&gt;. The idea was that in very large and complicated pattern matches, with many local variables, the &lt;code&gt;itself&lt;&#x2F;code&gt; keyword could always be used to refer to the innermost match value. The thinking was that this would make it easier to avoid mistakes such as returning &lt;code&gt;e0&lt;&#x2F;code&gt; instead of &lt;code&gt;e&lt;&#x2F;code&gt; or the like.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with this idea is at least three-fold: (i) it seems like overkill for a very specific problem, (ii) it is not worth it on the complexity and strangeness budget, and finally (iii) it is still brittle in the presence of nested pattern matches.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;potential-design-flaws&quot;&gt;Potential Design Flaws&lt;&#x2F;h2&gt;
&lt;p&gt;It is debatable whether the following feature is a design flaw or not.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;built-in-syntax-for-lists-sets-and-maps&quot;&gt;Built-in Syntax for Lists, Sets, and Maps&lt;&#x2F;h3&gt;
&lt;p&gt;Flix has a principle that states that the standard library should not be &quot;blessed&quot;. That is, the standard library should be independent of the Flix compiler and language. It should just be like any other library: A collection of Flix code.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, despite this principle, Flix has special syntax for Lists, Sets and Maps:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;flix&quot;&gt;1 :: 2 :: Nil
Set#{1, 2, 3}
Map#{1 -&amp;gt; 2, 3 -&amp;gt; 4}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which is built-in to the language. While technically these constructs are merely syntactic sugar for &lt;code&gt;Cons&lt;&#x2F;code&gt;, and calls to &lt;code&gt;Set.empty&lt;&#x2F;code&gt;, &lt;code&gt;Set.insert&lt;&#x2F;code&gt;, &lt;code&gt;Map.empty&lt;&#x2F;code&gt; and &lt;code&gt;Map.insert&lt;&#x2F;code&gt; there is no getting around the fact that this is a special kind of blessing of the standard library. In particular, it is &lt;em&gt;not&lt;&#x2F;em&gt; possible to define your own &lt;code&gt;Foo#...&lt;&#x2F;code&gt; syntax for anything.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
