Flix Programming Language Documentation

repository·master·Indexed 25 days ago

https://github.com/flix/flix

Flix is a statically typed, multi-paradigm programming language combining functional, imperative, and logic programming features. This documentation covers language syntax, naming conventions, and standard library patterns, as well as technical details on bytecode generation, the checkcast invariant, and effect system suspension. It also provides guides for building the compiler using Mill or IntelliJ IDEA and setting up the official VSCode extension.

Tokens
10K
Snippets
8
Records
89
Agent score
83%

What's inside Flix

  1. Understand the checkcast Invariant in Flix bytecode

    master

    The Flix compiler maintains a specific invariant during bytecode generation: compileExpr(e) must leave a value on the JVM stack whose verifier type is compatible with BackendType.toBackendType(e.tpe).

    Because Flix compiles enums, tuples, records, and structs to JVM classes with erased field types (using java.lang.Object), CHECKCAST instructions are required to narrow the JVM verifier type from Object to the actual runtime type when extracting values from these structures.

  2. Build and run the Flix compiler with IntelliJ IDEA

    master

    You can build and run the Flix compiler and standard library using IntelliJ IDEA.

    Project Setup

    1. Open IDEA and select "Get from VCS".
    2. Navigate to Settings | Build, Execution, Deployment | Build Tools and configure the following:
      • Set "Build and run using:" to IntelliJ IDEA.
      • Set "Run tests using:" to IntelliJ IDEA.

    Running the REPL

    To start the Flix REPL:

    1. Navigate to main/src/ca/uwaterloo/flix/Main.scala.
    2. Right-click on def main and select Run 'Main'.

    Compiling and running a Flix file

    To compile and run a specific Flix file containing a main function:

    1. Right-click on the def main in Main.scala.
    2. Select "Modify Run Configuration".
    3. Enter the target file name in the "Program arguments" field.
    1. Open IDEA and choose "Get from VCS"
    2. In "Settings | Build, Execution, Deployment | Build Tools":
        1. Set "Build and run using:" to "IntelliJ IDEA"
        2. Set "Run tests using:" to "IntelliJ IDEA"
  3. Manage NewObject casts in Let bindings

    master

    While most Let bindings do not perform casting, NewObject expressions (anonymous Java class construction) are an exception.

    Because the JVM verifier may fail to resolve the hierarchy of dynamically generated anonymous classes (e.g., Anon$42), it may fall back to Object. To ensure the verifier recognizes the correct superclass, the Let binding for a NewObject must include a cast to the declared superclass type.

  4. Flix Naming Conventions

    master

    Follow these naming conventions for Flix code:

    • Variables: Use short, typical one-letter names (e.g., o for Option, l for List).
    • Type Variables: Use a, b, c.
    • Effect Variables: Use ef, ef1, ef2, etc.
    • Trait Instances: Declare trait instances immediately below the type declaration, ordered as: Eq, Order, ToString.
  5. Understand effect system suspension and frame management

    master

    When using algebraic effects, Flix generates an applyFrame method to manage function state during suspension and resumption.

    Suspension Process

    1. Save (setPc): The current state is saved by cloning the closure, setting the pc (program counter) to the next resume address, and copying locals to erased fields (e.g., frame.l0 = slot4). Since these fields are Object, no casting is needed during saving.
    2. Return: The frame is attached to a Suspension and returned.

    Resumption Process

    1. Restore: The handler calls frame.applyFrame(value). The method uses loadFromField to load locals from the erased fields and casts them back to their real types.
    2. Narrowing (narrowLocals): At each pcPointLabel (resume site), the JVM verifier might have merged types, broadening them to Object. The narrowLocals operation immediately re-casts non-primitive locals to their declared types to ensure type safety in the resumed code.
  6. Language Syntax and Naming Conventions

    master

    Flix follows specific naming conventions for types and variables:

    • Type variables: lowercase (e.g., a, b)
    • Types: Uppercase (e.g., List[a], Int32)
    • Local variables and functions: lowercase
    • Enum constructors: Uppercase

    Other syntax features include:

    • String interpolation: Uses the ToString trait, e.g., "Hello ${name}".
    • Pipeline operator: Uses |> for chaining operations.
    • Infix application: Use backticks for infix function applications.
    • Program holes: Use ??? or ?name to denote incomplete code.
    • Set and Map literals: Use Set#{1, 2, 3} and Map#{1 => 2, 3 => 4}.
  7. Configure ScalaDoc formatting in IntelliJ

    master

    To ensure correct ScalaDoc formatting, adjust your IntelliJ IDEA settings: Go to Settings > Editor > Code Style > Scala > ScalaDoc and enable the option add additional space for leading asterisk.

  8. Scala Naming Conventions

    master

    Follow these naming conventions for Scala code:

    • Common Methods: Use patterns like visitExp, visitExps, visitPat, etc.
    • Variables:
      • Abbreviate long variable names (e.g., eff, tparam).
      • Name expressions sequentially (e.g., exp1, exp2, exp3) rather than using names like beginExp which become outdated.
    • Constructors: Generally do not abbreviate constructor names (e.g., Effect), with specific exceptions like TypeParam, Sig, and Def.
  9. Test the Flix VSCode extension

    master

    To test the VSCode integration, you must first configure the path to your VSCode project and build the necessary JAR.

    1. Create a .env file in the project root with the following content: VSCODE_PATH=/path/to/vscode/project
    2. Run the Mill command to build and copy the JAR: ./mill flix.vscode
    3. Open the directory in VSCode using File -> Open Folder ... to begin testing.
    VSCODE_PATH=/path/to/vscode/project
    ./mill flix.vscode
  10. Perform property-based testing with QuickCheck frameworks

    master

    Flix supports QuickCheck frameworks for property-based testing. Instead of defining individual test cases, you define properties that your code must satisfy. The framework then:

    1. Generates a large number of random inputs to test these properties.
    2. Explores edge cases to find potential bugs.
    3. Automatically simplifies failing inputs to find the simplest case that triggers the failure, aiding in efficient debugging.