DEV Community

Ingi
Ingi

Posted on

In Theory: Self-Correcting Software - Part 2

This article explores Plang, an intent-based programming language designed to interpret natural language. For more information, visit plang.is or take your first steps

In a previous article on self-correcting software, I demonstrated how Plang code can self-correct. It was a simple proof of concept, but let's dive deeper into how this works.

How Plang Works

Plang compiles into JSON files—essentially instructions—that are saved into a .pr file. This .pr file tells the Plang runtime how to execute your code. Keep this .pr file in mind as it plays a crucial role in what follows.

Example of a Basic Instruction:

- read file.txt to %content%
Enter fullscreen mode Exit fullscreen mode

This would generate a JSON instruction like so:

{
    "ModuleType":"FileModule",
    "FunctionName": "ReadTextFile",
    "Parameters": [{"path": "file.txt"}]
}
Enter fullscreen mode Exit fullscreen mode

The Plang runtime will load the appropriate FileModule, and if you examine the Program.cs file, you'll find a method called ReadTextFile.

This is where Plang is currently at, in version 0.1.

The Challenge: Refactoring and Compatibility

Now, imagine we want to refactor the method name from ReadTextFile to ReadContentOfTextFile in the Program.cs.

Any Plang code that uses the old method name(ReadTextFile) will break and throw an error like this:

Error:
    Message: Method 'ReadTextFile' could not be found. 'ReadTextFile' is defined in your instruction file
    Key: MissingMethod
Enter fullscreen mode Exit fullscreen mode

In the previous article, I showed how Plang can bind events to goals (functions) or steps (lines of code). We’ll use this feature to handle method refactoring gracefully.

Self-Correcting Code in Action

We start by creating an event listener that catches this specific error:

Events
- on any error where key="MissingMethod", call FixCode
Enter fullscreen mode Exit fullscreen mode

Step 1: Collect Available Methods

First create FixCode.goal and give it the title

FixCode
Enter fullscreen mode Exit fullscreen mode

Next, we want to resolve the MissingMethod error by finding the updated method in the FileModule.

We need to gather all available methods in FileModule. We can access what module caused the error from the %!step.ModuleType% property:

- get all available methods in %!step.ModuleType%, write to %methods%
Enter fullscreen mode Exit fullscreen mode

ProTip: In Plang, the %!step% variable always contains the current step running, including its ModuleType, which points to the FileModule. If you want to know what properties are in %!step%, just write it out - write out %!step%

This will include methods like ReadContentOfTextFile. Here's an example of what it might look like:

[
  {
    "Method": "public async Task<string> ReadContentOfTextFile(string path, string returnValueIfFileNotExisting = '', bool throwErrorOnNotFound = false, bool loadVariables = false, bool emptyVariableIfNotFound = false, string encoding = 'utf-8')",
    "Description": "Read the content from a file. Formerly ReadTextFile"
  },
  {
    "Method": "public async Task WriteToFile(string path, string content, bool overwrite = false, bool loadVariables = false, bool emptyVariableIfNotFound = false, string encoding = 'utf-8')",
    "Description": "Write content to a file"
  }
  ...
  ...
  ...
]
Enter fullscreen mode Exit fullscreen mode

Step 2: Read the Failing Instruction

Next, we read the instruction .pr file for the step that triggered the error:

- read %!step.AbsolutePrPath%, into %instructions%
Enter fullscreen mode Exit fullscreen mode

AbsolutePrPath is a property of the %!step% variable that points to the location of the .pr file on your hard drive

Step 3: Call the LLM to Fix the Code

We can now pass the problem to a language model (LLM) to update the method name:

- [llm] system: The user is attempting to execute code, but the method was not found, possibly due to renaming.
              These are the instructions to call the C# code: %instructions%
              These are the available methods: %methods%
              Rewrite the instructions
      user: %!error.Message%
      scheme: {instructions:string}
Enter fullscreen mode Exit fullscreen mode

With this input, the LLM can generate the corrected code and return it in the %instructions% variable.

Step 4: Write the Corrected Code

Finally, we overwrite the .pr file with the corrected code and re-execute the step:

- write %instructions% to %!step.AbsolutePrPath%
- retry step
Enter fullscreen mode Exit fullscreen mode

Final Solution:

The complete self-correcting code looks like this:

FixCode
- get all available methods in %!error.ModuleType%, write to %methods%
- read %!step.AbsolutePrPath%, into %instructions%
- [llm] system: The user is attempting to execute code, but the method was not found, possibly due to renaming.
              These are the instructions to call the C# code: %instructions%
              These are the available methods: %methods%
              Rewrite the instructions
      user: %!error.Message%
      scheme: {instructions:string}
- write %instructions% to %!step.AbsolutePrPath%
- retry step
Enter fullscreen mode Exit fullscreen mode

In-Theory Article

This is still theoretical—these modules aren't yet available in Plang, and some features like retry step and get all available methods aren't implemented. But once the language matures, this will work.

So why haven’t I implemented this yet? Well, Plang is evolving fast, and there are a thousand things to work on. But I wanted to outline this approach first.

Plang's Upgrade Path

This opens up a fascinating upgrade path for Plang. Since Plang is still in its early stages, breaking changes are common. This approach would allow upgrades to happen almost automatically, minimizing the need for manual fixes.

Of course, there's still a lot of engineering ahead, but the conceptual problem is solved.

Extending Plang with Modules

It's easy to extend Plang using modules. For example, to interact with Google Drive, you could install the Google.Drive module:

Start
- get list of all my files in "tAff2u44jU2nZgpJkbY5mSwW3" on Google Drive, %files%
- write out "List of all files: %files%"
- go through %files%, call ProcessFile

ProcessFile
- download file from Google Drive, fileId=%item.id%, save it to file/%item.name%
Enter fullscreen mode Exit fullscreen mode

Now imagine the module developer updates the API and renames methods. Thanks to our self-correcting system, your code would still work without any changes on your end.

A Word of Caution

As programmers, we’re naturally skeptical about automated fixes happening without confirmation. This is where unit tests come into play. But that’s a topic for another article.

More Information

Interested in learning more about Plang? Here are some useful resources to get started:

Top comments (0)