A RAPID program is a set of modules, and a module is a text file the controller keeps in memory. `robot.Rws.Rapid` loads and saves these files, reads and rewrites their source, and reports what the controller refused when it linked them.

Everything on this page that writes needs the `Rapid` [mastership](/abb/documentation/rws-mastership). Editing the source of a task that is running is possible, but the controller can refuse a change that would invalidate the program pointer.

## Program files

A program is a `.pgf` file naming the modules it holds. `GetProgram` returns the program of a task, `null` when the task holds none.

**C# : RapidProgramFiles**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidProgramFiles
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // The program the task holds, null when it holds none
        RapidProgramInfo program = robot.Rws.Rapid.GetProgram("T_ROB1");
        if (program != null)
            Console.WriteLine(program.Name + ", entry point " + program.EntryPoint);

        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // The program file has to be on the controller already.
            // Upload it first with robot.Rws.File.
            robot.Rws.Rapid.LoadProgram("T_ROB1", "$HOME/myprogram.pgf", RapidProgramLoadMode.Replace);

            // Write every module of the task into a directory of the controller
            robot.Rws.Rapid.SaveProgram("T_ROB1", "$HOME/myprograms");

            robot.Rws.Rapid.SetProgramName("T_ROB1", "myprogram");
            robot.Rws.Rapid.SetEntryPoint("T_ROB1", "main");

            robot.Rws.Rapid.UnloadProgram("T_ROB1");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        // Loading returns before the controller has finished, so read what it refused
        foreach (RapidBuildError error in robot.Rws.Rapid.GetBuildErrors("T_ROB1"))
            Console.WriteLine(error.ModuleName + " " + error.Row + "," + error.Column + ": " + error.Error);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidProgramFiles**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_program_load_mode import RapidProgramLoadMode

robot = AbbController()
robot.connect("192.168.0.1")

##
# The program the task holds, None when it holds none
program = robot.rws.rapid.get_program("T_ROB1")
if program is not None:
    print(f"{program.name}, entry point {program.entry_point}")

robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # The program file has to be on the controller already.
    # Upload it first with robot.rws.file.
    robot.rws.rapid.load_program("T_ROB1", "$HOME/myprogram.pgf", RapidProgramLoadMode.Replace)

    # Write every module of the task into a directory of the controller
    robot.rws.rapid.save_program("T_ROB1", "$HOME/myprograms")

    robot.rws.rapid.set_program_name("T_ROB1", "myprogram")
    robot.rws.rapid.set_entry_point("T_ROB1", "main")

    robot.rws.rapid.unload_program("T_ROB1")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

# Loading returns before the controller has finished, so read what it refused
for error in robot.rws.rapid.get_build_errors("T_ROB1"):
    print(f"{error.module_name} {error.row},{error.column}: {error.error}")
##

robot.disconnect()
```

| `RapidProgramLoadMode` | What happens to the modules already loaded           |
| ---------------------- | ---------------------------------------------------- |
| `Add`                  | They are kept, the modules of the program are added  |
| `Replace`              | Everything the task holds is replaced by the program |

Points to know:

- The file has to be on the file system of the controller already. Upload it first with the [file system service](/abb/documentation/rws-files).
- `LoadProgram` returns before the controller has finished loading. Read the task state and the build errors afterwards, do not assume the program is ready.
- `SaveProgram` writes the modules of the task into a directory of the controller, not on your PC. Download them afterwards.
- `SetEntryPoint` sets the routine `ResetProgramPointer` goes back to, usually `main`.
- Loading one module instead of a whole program is done with `LoadModule`, see [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks).

**Methods of RapidService**
```csharp
// Loads a program into a task (synchronous)
void LoadProgram(string task, string programPath, RapidProgramLoadMode loadMode = RapidProgramLoadMode.Add);

// Saves the program of a task to the file system of the controller (synchronous)
void SaveProgram(string task, string path);

// Sets the routine the program pointer moves to when it is reset (synchronous)
void SetEntryPoint(string task, string routine);

// Renames the program of a task (synchronous)
void SetProgramName(string task, string name);

// Unloads the program of a task (synchronous)
void UnloadProgram(string task);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidProgramInfo**
```csharp
public class RapidProgramInfo {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidProgramInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidProgramInfo()

    // Routine the program pointer moves to when it is reset, null when the controller did not report it
    public string EntryPoint { get; set; }

    // Name of the program, null when the controller did not report it
    public string Name { get; set; }

    // Returns a string representation of this program
    public override string ToString()
}
```

**Members of Rws.Data.RapidProgramLoadMode**
```csharp
public enum RapidProgramLoadMode {
    // Keep the modules already loaded and add the ones of the program
    Add = 0

    // Replace everything the task holds with the program
    Replace = 1
}
```

## Modules of a task

`GetModules` lists the modules a task holds. `GetModule` gives the file a module came from and the properties declared on it.

**C# : RapidModuleList**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidModuleList
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        foreach (RapidModuleItem module in robot.Rws.Rapid.GetModules("T_ROB1"))
        {
            Console.WriteLine(module.Name + " " + module.Type);   // ProgramModule or SystemModule

            // The file the module came from and the properties declared on it
            RapidModuleInfo info = robot.Rws.Rapid.GetModule("T_ROB1", module.Name);
            Console.WriteLine(info.FileName);

            foreach (RapidModuleAttribute attribute in info.Attributes)
                Console.WriteLine("   " + attribute);             // SystemModule, NoStepIn, ...

            // How big the source is, in lines and columns
            RapidModuleExtension size = robot.Rws.Rapid.GetModuleExtension("T_ROB1", module.Name);
            Console.WriteLine(size.LineCount + " lines, " + size.MaxColumnCount + " columns");

            // A counter that only moves when the module changes, cheaper than reading it again
            Console.WriteLine(robot.Rws.Rapid.GetModuleChangeCount("T_ROB1", module.Name));
        }

        // Which of these properties this module accepts
        RapidModuleAttribute[] possible = robot.Rws.Rapid.GetPossibleModuleAttributes(
            "T_ROB1", "MainModule", RapidModuleAttribute.NoStepIn, RapidModuleAttribute.ViewOnly);
        Console.WriteLine(possible.Length);

        // Write one module as a file of the controller, the extension is added by the controller
        robot.Rws.Rapid.SaveModule("T_ROB1", "MainModule", "MainModule", "$HOME");
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidModuleList**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.rapid_module_attribute import RapidModuleAttribute

robot = AbbController()
robot.connect("192.168.0.1")

##
for module in robot.rws.rapid.get_modules("T_ROB1"):
    print(f"{module.name} {module.type}")  # ProgramModule or SystemModule

    # The file the module came from and the properties declared on it
    info = robot.rws.rapid.get_module("T_ROB1", module.name)
    print(info.file_name)

    for attribute in info.attributes:
        print("   " + str(attribute))      # SystemModule, NoStepIn, ...

    # How big the source is, in lines and columns
    size = robot.rws.rapid.get_module_extension("T_ROB1", module.name)
    print(f"{size.line_count} lines, {size.max_column_count} columns")

    # A counter that only moves when the module changes, cheaper than reading it again
    print(robot.rws.rapid.get_module_change_count("T_ROB1", module.name))

# Which of these properties this module accepts
possible = robot.rws.rapid.get_possible_module_attributes(
    "T_ROB1", "MainModule", [RapidModuleAttribute.NoStepIn, RapidModuleAttribute.ViewOnly])
print(len(possible))

# Write one module as a file of the controller, the extension is added by the controller
robot.rws.rapid.save_module("T_ROB1", "MainModule", "MainModule", "$HOME")
##

robot.disconnect()
```

| `RapidModuleAttribute` | What the module declares                                           |
| ---------------------- | ------------------------------------------------------------------ |
| `SystemModule`         | The module belongs to the system, it is not saved with the program |
| `ReadOnly`             | The source cannot be changed                                       |
| `ViewOnly`             | The source can be read but not changed                             |
| `NoView`               | The source cannot even be read                                     |
| `NoStepIn`             | Stepping does not enter the routines of the module                 |
| `Encoded`              | The source is stored encoded                                       |

`GetModuleChangeCount` returns a counter that only moves when the module changes. Comparing it with the previous reading is much cheaper than downloading the source again to find out that nothing moved. `GetModuleExtension` gives the number of lines and the longest line of the source.

### Read and edit the source

> **Available on** RWS 1.0 (IRC5) : yes | RWS 2.0 (OmniCore) : yes. On an IRC5 reading the whole source costs two requests and DeclaredLength stays empty.

**C# : RapidModuleSource**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidModuleSource
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // The whole source of the module
        RapidModuleText source = robot.Rws.Rapid.GetModuleText("T_ROB1", "MainModule");
        Console.WriteLine(source.Text);
        Console.WriteLine(source.ChangeCount);

        // Only a few lines. Rows and columns are counted from 1, and the controller clamps
        // the end of the range to what the module really holds.
        Console.WriteLine(robot.Rws.Rapid.GetModuleTextRange("T_ROB1", "MainModule", 1, 1, 10, 1));

        // Where a piece of text sits, Found is false when it is nowhere
        RapidTextPosition found = robot.Rws.Rapid.SearchModuleText("T_ROB1", "MainModule", "MoveJ");
        Console.WriteLine(found.Found + " " + found.Row + "," + found.Column);

        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // Insert one line after a range, leaving the rest of the module alone
            RapidSetTextRangeResult result = robot.Rws.Rapid.SetModuleTextRange(
                "T_ROB1", "MainModule",
                RapidTextReplaceMode.After, RapidTextQueryMode.Try,
                5, 1, 5, 1,
                "    reg1 := 0;\r\n");

            // Rewriting the line that declares the module renames it
            Console.WriteLine(result.ModuleRenamed + " " + result.NewModuleName);

            // Replace the whole source
            robot.Rws.Rapid.SetModuleText("T_ROB1", "MainModule",
                "MODULE MainModule\r\n  PROC main()\r\n  ENDPROC\r\nENDMODULE\r\n");
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidModuleSource**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_text_query_mode import RapidTextQueryMode
from underautomation.abb.rws.data.rapid_text_replace_mode import RapidTextReplaceMode

robot = AbbController()
robot.connect("192.168.0.1")

##
# The whole source of the module
source = robot.rws.rapid.get_module_text("T_ROB1", "MainModule")
print(source.text)
print(source.change_count)

# Only a few lines. Rows and columns are counted from 1, and the controller clamps
# the end of the range to what the module really holds.
print(robot.rws.rapid.get_module_text_range("T_ROB1", "MainModule", 1, 1, 10, 1))

# Where a piece of text sits, found is False when it is nowhere
found = robot.rws.rapid.search_module_text("T_ROB1", "MainModule", "MoveJ")
print(f"{found.found} {found.row},{found.column}")

robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # Insert one line after a range, leaving the rest of the module alone
    result = robot.rws.rapid.set_module_text_range(
        "T_ROB1", "MainModule",
        RapidTextReplaceMode.After, RapidTextQueryMode.Try_,
        5, 1, 5, 1,
        "    reg1 := 0;\r\n")

    # Rewriting the line that declares the module renames it
    print(f"{result.module_renamed} {result.new_module_name}")

    # Replace the whole source
    robot.rws.rapid.set_module_text("T_ROB1", "MainModule",
        "MODULE MainModule\r\n  PROC main()\r\n  ENDPROC\r\nENDMODULE\r\n")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

Rows and columns are counted from 1, not from 0. The controller clamps the end of a range to what the module really holds, so a range running past the last line is not an error.

`SetModuleTextRange` writes into a range and returns what the controller did with the change.

| `RapidTextReplaceMode` | Where the new text goes                                |
| ---------------------- | ------------------------------------------------------ |
| `Replace`              | The range is replaced by the new text                  |
| `Before`               | The new text is inserted before the range, which stays |
| `After`                | The new text is inserted after the range, which stays  |

| `RapidTextQueryMode` | When the program pointer would become invalid                  |
| -------------------- | -------------------------------------------------------------- |
| `Try`                | The controller refuses the change                              |
| `Force`              | The controller applies it anyway and drops the program pointer |

Rewriting the line that declares the module renames it. This is why the result carries `ModuleRenamed` and `NewModuleName`. Use the new name in the calls that follow, the old one no longer exists.

`SearchModuleText` reports row and column 0 when it finds nothing, it does not fail. Test `Found` rather than the row.

`SaveModule` writes one module as a file of the controller. The controller adds the extension itself, so pass `MainModule` and not `MainModule.mod`.

**Methods of RapidService**
```csharp
// Gets the file a module came from and the properties declared on it (synchronous)
RapidModuleInfo GetModule(string task, string module);

// Gets the counter the controller increments whenever a module changes (synchronous) Comparing it with what a previous reading gave is cheaper than fetching the source again to find out that nothing changed.
int GetModuleChangeCount(string task, string module);

// Gets how many lines and columns the source of a module holds (synchronous) This is what it takes to ask for the whole of it with Int32%2cSystem.Int32).
RapidModuleExtension GetModuleExtension(string task, string module);

// Gets the declaration the controller finds at a position of a module (synchronous)
RapidModuleSymbol GetModuleSymbol(string task, string module, int row, int column);

// Gets the source of a module (synchronous)
RapidModuleText GetModuleText(string task, string module);

// Gets a range of the source of a module (synchronous)
string GetModuleTextRange(string task, string module, int startRow, int startColumn, int endRow, int endColumn);

// Gets the modules loaded into a task (synchronous)
RapidModuleItem[] GetModules(string task);

// Gets which of the requested properties may be declared on a module (synchronous)
RapidModuleAttribute[] GetPossibleModuleAttributes(string task, string module, params RapidModuleAttribute[] attributes);

// Saves a module to the file system of the controller (synchronous)
void SaveModule(string task, string module, string name, string path);

// Finds where a piece of text sits in the source of a module (synchronous)
RapidTextPosition SearchModuleText(string task, string module, string text, int startRow = 1, int startColumn = 1);

// Replaces the whole source of a module (synchronous)
void SetModuleText(string task, string module, string text);

// Writes text into a range of the source of a module (synchronous)
RapidSetTextRangeResult SetModuleTextRange(string task, string module, RapidTextReplaceMode replaceMode, RapidTextQueryMode queryMode, int startRow, int startColumn, int endRow, int endColumn, string text);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidModuleItem**
```csharp
public class RapidModuleItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleItem" data-throw-if-not-resolved="false"></xref> class
    public RapidModuleItem()

    // Name of the module, for example "MainModule"
    public string Name { get; set; }

    // Returns a string representation of this module
    public override string ToString()

    // Whether the module belongs to the program or to the system
    public RapidModuleType Type { get; set; }
}
```

**Members of Rws.Data.RapidModuleInfo**
```csharp
public class RapidModuleInfo : RapidModuleItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidModuleInfo()

    // Number of properties declared on the module
    public int AttributeCount { get; }

    // Properties declared on the module, empty when it declares none
    public RapidModuleAttribute[] Attributes { get; set; }

    // Name of the file the module was loaded from, for example "MainModule.mod"
    public string FileName { get; set; }
}
```

**Members of Rws.Data.RapidModuleText**
```csharp
public class RapidModuleText {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleText" data-throw-if-not-resolved="false"></xref> class
    public RapidModuleText()

    // Counter the controller increments whenever the module changes, null when it did not report it
    public int? ChangeCount { get; set; }

    // Length the controller declares for the module, null when it did not report it.
    // 
    // <p>This is the size the controller reserves for the module and not the length of
    // <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleText.Text" data-throw-if-not-resolved="false"></xref>, so the two normally differ.</p>
    public int? DeclaredLength { get; set; }

    // Source of the module
    public string Text { get; set; }

    // Returns a string representation of this module source
    public override string ToString()
}
```

**Members of Rws.Data.RapidModuleExtension**
```csharp
public class RapidModuleExtension {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleExtension" data-throw-if-not-resolved="false"></xref> class
    public RapidModuleExtension()

    // Counter the controller increments whenever the module changes, null when it did not report it
    public int? ChangeCount { get; set; }

    // Number of lines the module holds, null when the controller did not report it
    public int? LineCount { get; set; }

    // Length of the longest line of the module, null when the controller did not report it
    public int? MaxColumnCount { get; set; }

    // Returns a string representation of this extension
    public override string ToString()
}
```

**Members of Rws.Data.RapidSetTextRangeResult**
```csharp
public class RapidSetTextRangeResult {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidSetTextRangeResult" data-throw-if-not-resolved="false"></xref> class
    public RapidSetTextRangeResult()

    // Counter the controller incremented for the change, null when it did not report it
    public int? ChangeCount { get; set; }

    // Whether the change renamed the module
    public bool ModuleRenamed { get; set; }

    // Name the module now has, empty when the change did not rename it
    public string NewModuleName { get; set; }

    // Returns a string representation of this result
    public override string ToString()
}
```

**Members of Rws.Data.RapidTextPosition**
```csharp
public class RapidTextPosition {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidTextPosition" data-throw-if-not-resolved="false"></xref> class
    public RapidTextPosition()

    // Column of the position, 0 when the search found nothing
    public int Column { get; set; }

    // Whether the position points at something, which it does not when a search found nothing
    public bool Found { get; }

    // Line of the position, 0 when the search found nothing
    public int Row { get; set; }

    // Returns a string representation of this position
    public override string ToString()
}
```

**Members of Rws.Data.RapidModuleType**
```csharp
public enum RapidModuleType {
    // A module of the program, saved and loaded with it
    ProgramModule = 1

    // A module of the system, which survives loading another program
    SystemModule = 2

    // The controller reported a type this library does not know
    Unknown = 0
}
```

**Members of Rws.Data.RapidModuleAttribute**
```csharp
public enum RapidModuleAttribute {
    // The source of the module is encoded and cannot be read back
    Encoded = 2

    // Execution may not step into the routines of the module
    NoStepIn = 4

    // The source of the module may not be displayed
    NoView = 3

    // The module may not be changed
    ReadOnly = 6

    // The module belongs to the system rather than to the program
    SystemModule = 1

    // The controller reported an attribute this library does not know
    Unknown = 0

    // The source may be displayed but not changed
    ViewOnly = 5
}
```

**Members of Rws.Data.RapidTextReplaceMode**
```csharp
public enum RapidTextReplaceMode {
    // Insert the new text after the range, leaving it in place
    After = 0

    // Insert the new text before the range, leaving it in place
    Before = 1

    // Replace the range with the new text
    Replace = 2
}
```

**Members of Rws.Data.RapidTextQueryMode**
```csharp
public enum RapidTextQueryMode {
    // Apply the change even when it invalidates the program pointer
    Force = 0

    // Apply the change only when the program pointer survives it
    Try = 1
}
```

## Build errors

Linking a program never fails the request itself. The controller accepts it, then reports what it refused. `GetBuildErrors` returns one entry per error, with the module, the position and the message.

**C# : RapidBuildErrors**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidBuildErrors
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // The controller answers at most thirty errors at a time, read the next ones by paging
        int start = 0;
        RapidBuildError[] errors = robot.Rws.Rapid.GetBuildErrors("T_ROB1", start, 30);

        while (errors.Length > 0)
        {
            foreach (RapidBuildError error in errors)
            {
                Console.WriteLine(error.ModuleName + " " + error.Row + "," + error.Column);
                Console.WriteLine("   " + error.Error);
            }

            start += errors.Length;
            errors = robot.Rws.Rapid.GetBuildErrors("T_ROB1", start, 30);
        }

        // An empty answer and a task state of Linked mean the program is runnable
        Console.WriteLine(robot.Rws.Rapid.GetTask("T_ROB1").TaskState);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidBuildErrors**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# The controller answers at most thirty errors at a time, read the next ones by paging
start = 0
errors = robot.rws.rapid.get_build_errors("T_ROB1", start, 30)

while len(errors) > 0:
    for error in errors:
        print(f"{error.module_name} {error.row},{error.column}")
        print("   " + error.error)

    start += len(errors)
    errors = robot.rws.rapid.get_build_errors("T_ROB1", start, 30)

# An empty answer and a task state of Linked mean the program is runnable
print(robot.rws.rapid.get_task("T_ROB1").task_state)
##

robot.disconnect()
```

The controller returns at most thirty errors at a time, whatever larger limit is asked for. Use `start` and `limit` to read the rest. An empty array means the program linked cleanly, and the task state then becomes `Linked`.

`BuildTask` itself is described in [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks).

**Methods of RapidService**
```csharp
// Gets the errors the controller found while linking the program of a task (synchronous)
RapidBuildError[] GetBuildErrors(string task, int? start = null, int? limit = null);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidBuildError**
```csharp
public class RapidBuildError {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidBuildError" data-throw-if-not-resolved="false"></xref> class
    public RapidBuildError()

    // Column the error was found at, null when the controller did not report it
    public int? Column { get; set; }

    // Description of the error as the controller worded it
    public string Error { get; set; }

    // Numeric identifier of the error, null when the controller did not report it
    public int? ErrorNumber { get; set; }

    // Name of the module the error was found in
    public string ModuleName { get; set; }

    // Line the error was found at, null when the controller did not report it
    public int? Row { get; set; }

    // Returns a string representation of this build error
    public override string ToString()
}
```

## Breakpoints

`SetBreakpoint` places a breakpoint at a position of a module. The controller snaps it to the whole instruction holding that position, so the range it answers is normally wider than what was asked for.

**C# : RapidBreakpoints**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidBreakpoints
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            // The controller snaps the breakpoint to the whole instruction holding the
            // position, so the range it answers is normally wider than what was asked for
            RapidBreakpoint placed = robot.Rws.Rapid.SetBreakpoint("T_ROB1", "MainModule", 12, 1);
            Console.WriteLine(placed.StartRow + "," + placed.StartColumn + " -> " +
                              placed.EndRow + "," + placed.EndColumn);
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }

        foreach (RapidBreakpoint breakpoint in robot.Rws.Rapid.GetBreakpoints("T_ROB1"))
            Console.WriteLine(breakpoint.ModuleName + " " + breakpoint.StartRow);

        // A breakpoint only stops the program when execution was started with stopAtBreakpoint
        robot.Rws.Rapid.Start(RapidRegainMode.Continue, RapidExecutionMode.Continue,
                              RapidExecutionCycle.Forever, RapidStartCondition.None, true, false);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidBreakpoints**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain
from underautomation.abb.rws.data.rapid_execution_cycle import RapidExecutionCycle
from underautomation.abb.rws.data.rapid_execution_mode import RapidExecutionMode
from underautomation.abb.rws.data.rapid_regain_mode import RapidRegainMode
from underautomation.abb.rws.data.rapid_start_condition import RapidStartCondition

robot = AbbController()
robot.connect("192.168.0.1")

##
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    # The controller snaps the breakpoint to the whole instruction holding the
    # position, so the range it answers is normally wider than what was asked for
    placed = robot.rws.rapid.set_breakpoint("T_ROB1", "MainModule", 12, 1)
    print(f"{placed.start_row},{placed.start_column} -> {placed.end_row},{placed.end_column}")
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)

for breakpoint in robot.rws.rapid.get_breakpoints("T_ROB1"):
    print(f"{breakpoint.module_name} {breakpoint.start_row}")

# A breakpoint only stops the program when execution was started with stopAtBreakpoint
robot.rws.rapid.start(RapidRegainMode.Continue_, RapidExecutionMode.Continue_,
                      RapidExecutionCycle.Forever, RapidStartCondition.None_, True, False)
##

robot.disconnect()
```

A breakpoint only stops the program when execution was started with `stopAtBreakpoint` set to `true`, see [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks). Editing the source moves the positions, so read the breakpoints again after a change.

**Methods of RapidService**
```csharp
// Gets the breakpoints set in the program of a task (synchronous)
RapidBreakpoint[] GetBreakpoints(string task, int? start = null, int? limit = null);

// Sets a breakpoint at a position of a module (synchronous)
RapidBreakpoint SetBreakpoint(string task, string module, int row, int column);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidBreakpoint**
```csharp
public class RapidBreakpoint {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidBreakpoint" data-throw-if-not-resolved="false"></xref> class
    public RapidBreakpoint()

    // Column the breakpoint ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the breakpoint ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // Name of the module the breakpoint sits in, null when the controller did not report it
    public string ModuleName { get; set; }

    // Column the breakpoint starts at, null when the controller did not report it
    public int? StartColumn { get; set; }

    // Line the breakpoint starts at, null when the controller did not report it
    public int? StartRow { get; set; }

    // Returns a string representation of this breakpoint
    public override string ToString()
}
```

## Modify a taught position

This is the teaching gesture of the FlexPendant: jog the robot where it should go, then write that position back into the motion instruction of the program.

**C# : RapidModifyPosition**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidModifyPosition
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // How many motion instructions of this range can be rewritten
        RapidModifiablePositions modifiable =
            robot.Rws.Rapid.GetModifiablePositions("T_ROB1", "MainModule", 1, 1, 40, 1);
        Console.WriteLine(modifiable.ModifiableLineCount);

        // Every one of them, in every task of the system
        foreach (RapidModifiablePositionItem item in robot.Rws.Rapid.GetAllModifiablePositions())
            Console.WriteLine(item.TaskName + "/" + item.ModuleName + " line " + item.StartRow);

        // Jog the robot where it should go, then write that position into the program
        robot.Rws.Mastership.Request(MastershipDomain.Rapid);
        try
        {
            robot.Rws.Rapid.ModifyPosition("T_ROB1", "MainModule", 12, 1, 12, 1, true, true, false);
        }
        finally
        {
            robot.Rws.Mastership.Release(MastershipDomain.Rapid);
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidModifyPosition**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.mastership_domain import MastershipDomain

robot = AbbController()
robot.connect("192.168.0.1")

##
# How many motion instructions of this range can be rewritten
modifiable = robot.rws.rapid.get_modifiable_positions("T_ROB1", "MainModule", 1, 1, 40, 1)
print(modifiable.modifiable_line_count)

# Every one of them, in every task of the system
for item in robot.rws.rapid.get_all_modifiable_positions():
    print(f"{item.task_name}/{item.module_name} line {item.start_row}")

# Jog the robot where it should go, then write that position into the program
robot.rws.mastership.request(MastershipDomain.Rapid)
try:
    robot.rws.rapid.modify_position("T_ROB1", "MainModule", 12, 1, 12, 1, True, True, False)
finally:
    robot.rws.mastership.release(MastershipDomain.Rapid)
##

robot.disconnect()
```

`GetModifiablePositions` says how many motion instructions of a range can be rewritten, `GetAllModifiablePositions` lists every one of them in every task of the system. Read one of the two before writing, so you know what is about to change.

- `checkLimits` makes the controller refuse a position outside the working range.
- `checkDeactivatedAxes` makes it refuse to rewrite an axis that is deactivated, and `allowDeactivated` rewrites it anyway.
- `ModifyAllPositions` rewrites everything at once. The controller only accepts it from a client it considers local.

Jogging the robot to the position is done with the [motion system service](/abb/documentation/rws-motion), and it needs the `Motion` [mastership](/abb/documentation/rws-mastership), which is a different domain from `Rapid`.

**Methods of RapidService**
```csharp
// Gets every motion instruction of the system whose position can be rewritten to where the robot currently stands, wherever in whichever task it sits (synchronous)
RapidModifiablePositionItem[] GetAllModifiablePositions();

// Gets how many motion instructions of a range can have their position rewritten to where the robot currently stands (synchronous)
RapidModifiablePositions GetModifiablePositions(string task, string module, int startRow, int startColumn, int endRow, int endColumn);

// Rewrites the positions of every motion instruction of the system that can be rewritten, to where the robot currently stands (synchronous)
void ModifyAllPositions(bool checkLimits = true, bool checkDeactivatedAxes = true);

// Rewrites the positions of the motion instructions of a range to where the robot currently stands (synchronous) This is the teaching gesture: jog the robot where it should go, then write that position back into the program.
void ModifyPosition(string task, string module, int startRow, int startColumn, int endRow, int endColumn, bool checkLimits = true, bool checkDeactivatedAxes = true, bool allowDeactivated = false);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidModifiablePositions**
```csharp
public class RapidModifiablePositions {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModifiablePositions" data-throw-if-not-resolved="false"></xref> class
    public RapidModifiablePositions()

    // Column the modifiable range ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the modifiable range ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // Number of motion instructions of the range whose position can be rewritten
    public int ModifiableLineCount { get; set; }

    // Column the modifiable range starts at, null when the controller did not report it
    public int? StartColumn { get; set; }

    // Line the modifiable range starts at, null when the controller did not report it
    public int? StartRow { get; set; }

    // Returns a string representation of this result
    public override string ToString()
}
```

**Members of Rws.Data.RapidModifiablePositionItem**
```csharp
public class RapidModifiablePositionItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModifiablePositionItem" data-throw-if-not-resolved="false"></xref> class
    public RapidModifiablePositionItem()

    // Column the instruction ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the instruction ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // Name of the module holding the instruction
    public string ModuleName { get; set; }

    // Column the instruction starts at, null when the controller did not report it
    public int? StartColumn { get; set; }

    // Line the instruction starts at, null when the controller did not report it
    public int? StartRow { get; set; }

    // Name of the task holding the module
    public string TaskName { get; set; }

    // Returns a string representation of this instruction
    public override string ToString()
}
```

## Write an editor

The last group of methods exists for the applications that edit RAPID, not for the ones that drive a robot. They give what an editor needs: what is declared at a position, the arguments of a call, a complete instruction ready to be written, and the palette an operator picks an instruction from.

**C# : RapidSourceNavigation**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidSourceNavigation
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // What is declared at this position of the source, null when nothing is
        RapidModuleSymbol symbol = robot.Rws.Rapid.GetModuleSymbol("T_ROB1", "MainModule", 12, 5);
        if (symbol != null)
            Console.WriteLine(symbol.Name + " " + symbol.SymbolType + " " + symbol.DataType);

        // The routine called at this position, and the arguments of that call
        RapidRoutineInfo routine = robot.Rws.Rapid.GetRoutine("T_ROB1", "MainModule", 12, 5);
        Console.WriteLine(routine.Name + " " + routine.ParameterCount);

        foreach (RapidRoutineArgument argument in
                 robot.Rws.Rapid.GetRoutineArguments("T_ROB1", "MainModule", 12, 5))
        {
            Console.WriteLine(argument.DataType + " at " + argument.StartRow + "," + argument.StartColumn);
        }

        // A complete instruction ready to be written, instead of a bare keyword
        RapidInstructionTemplate template = robot.Rws.Rapid.GetInstructionTemplate("T_ROB1", "MainModule", "MoveJ");
        foreach (RapidInstructionTemplateArgument argument in template.Arguments)
            Console.WriteLine(argument.Name + " = " + argument.Value + " (" + argument.DataType + ")");

        // Where the parts of an object begin and end, given the whole span of that object
        RapidObjectChild children = robot.Rws.Rapid.GetObjectChildren("T_ROB1", "MainModule", 1, 1, 40, 1);
        foreach (RapidObjectChildRange range in children.Ranges)
            Console.WriteLine(range.Name + ": " + range.Range);

        // Where one of the lists an object holds sits, without reading the module
        RapidObjectListExtension list = robot.Rws.Rapid.GetObjectListExtension(
            "RAPID/T_ROB1/MainModule", RapidObjectListType.RoutineDeclarations);
        Console.WriteLine(list.List + " first " + list.First + " last " + list.Last);
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidSourceNavigation**
```python
from underautomation.abb.abb_controller import AbbController
from underautomation.abb.rws.data.rapid_object_list_type import RapidObjectListType

robot = AbbController()
robot.connect("192.168.0.1")

##
# What is declared at this position of the source, None when nothing is
symbol = robot.rws.rapid.get_module_symbol("T_ROB1", "MainModule", 12, 5)
if symbol is not None:
    print(f"{symbol.name} {symbol.symbol_type} {symbol.data_type}")

# The routine called at this position, and the arguments of that call
routine = robot.rws.rapid.get_routine("T_ROB1", "MainModule", 12, 5)
print(f"{routine.name} {routine.parameter_count}")

for argument in robot.rws.rapid.get_routine_arguments("T_ROB1", "MainModule", 12, 5):
    print(f"{argument.data_type} at {argument.start_row},{argument.start_column}")

# A complete instruction ready to be written, instead of a bare keyword
template = robot.rws.rapid.get_instruction_template("T_ROB1", "MainModule", "MoveJ")
for argument in template.arguments:
    print(f"{argument.name} = {argument.value} ({argument.data_type})")

# Where the parts of an object begin and end, given the whole span of that object
children = robot.rws.rapid.get_object_children("T_ROB1", "MainModule", 1, 1, 40, 1)
for item in children.ranges:
    print(f"{item.name}: {item.range}")

# Where one of the lists an object holds sits, without reading the module
object_list = robot.rws.rapid.get_object_list_extension(
    "RAPID/T_ROB1/MainModule", RapidObjectListType.RoutineDeclarations)
print(f"{object_list.list} first {object_list.first} last {object_list.last}")
##

robot.disconnect()
```

`GetModuleSymbol` returns the declaration found at a position, `null` when there is none. `GetRoutine` and `GetRoutineArguments` work on a position sitting on a routine call, and the controller refuses the request when it does not.

`GetInstructionTemplate` returns a complete instruction with the arguments the controller suggests, instead of a bare keyword. `GetObjectChildren` and `GetObjectListExtension` give where the parts of an object begin and end, which is how an editor jumps to the declarations of a module without reading the whole source.

**C# : RapidEditorPalette**
```csharp
using UnderAutomation.ABB;
using UnderAutomation.ABB.Rws.Data;

public class RapidEditorPalette
{
    static void Main()
    {
        AbbController robot = new AbbController();
        robot.Connect("192.168.0.1");

        /**/
        // Categories of the instruction palette, the same ones an editor shows
        foreach (RapidPalletHeadItem head in robot.Rws.Rapid.GetPalletHeads("T_ROB1"))
        {
            Console.WriteLine(head.Number + ": " + head.Name);

            // Instructions of that category
            foreach (RapidPalletItem item in robot.Rws.Rapid.GetPallet("T_ROB1", head.Number.Value))
                Console.WriteLine("   " + item.Name + " " + item.Instruction);
        }

        // Types the controller suggests for one argument of an instruction
        foreach (RapidPreferredDataTypeItem type in
                 robot.Rws.Rapid.GetPreferredDataTypes("T_ROB1", "AliasIO", "FromSignal"))
        {
            Console.WriteLine(type.Name + " (" + type.DataType + ")");
        }
        /**/

        robot.Disconnect();
    }
}
```

**Python : RapidEditorPalette**
```python
from underautomation.abb.abb_controller import AbbController

robot = AbbController()
robot.connect("192.168.0.1")

##
# Categories of the instruction palette, the same ones an editor shows
for head in robot.rws.rapid.get_pallet_heads("T_ROB1"):
    print(f"{head.number}: {head.name}")

    # Instructions of that category
    for item in robot.rws.rapid.get_pallet("T_ROB1", head.number):
        print(f"   {item.name} {item.instruction}")

# Types the controller suggests for one argument of an instruction
for data_type in robot.rws.rapid.get_preferred_data_types("T_ROB1", "AliasIO", "FromSignal"):
    print(f"{data_type.name} ({data_type.data_type})")
##

robot.disconnect()
```

`GetPalletHeads` returns the categories of the instruction palette, `GetPallet` the instructions of one category, and `GetPreferredDataTypes` the types that fit one argument of an instruction.

**Methods of RapidService**
```csharp
// Gets the template the controller suggests for an instruction or a data type: the arguments to write and the values to write them with (synchronous) This is what an editor uses to insert a complete, valid instruction rather than a bare keyword.
RapidInstructionTemplate GetInstructionTemplate(string task, string module, string name, bool isDataType = false, int? row = null, int? column = null, int? parameterNumber = null, int? alternativeNumber = null);

// Gets the parts a RAPID object is made of and where each of them sits in the source (synchronous) Pass the whole span of the object to get its parts; an editor uses this to know where the name, the attributes and the declaration lists of a module begin and end.
RapidObjectChild GetObjectChildren(string task, string module, int startLine, int startColumn, int endLine, int endColumn);

// Gets where one of the lists a RAPID object holds sits in the source: the span of the whole list, and the spans of its first and last elements (synchronous) An editor uses this to jump to the beginning or the end of a list without reading the whole module.
RapidObjectListExtension GetObjectListExtension(string symbolUrl, RapidObjectListType type = RapidObjectListType.Statements);

// Gets the entries of one category of the instruction palette (synchronous)
RapidPalletItem[] GetPallet(string task, int palletNumber, int? start = null, int? limit = null);

// Gets the categories of the instruction palette an editor offers (synchronous)
RapidPalletHeadItem[] GetPalletHeads(string task, int? start = null, int? limit = null);

// Gets the data types the controller suggests for one argument of an instruction (synchronous) An editor uses this to offer only the types that fit where the operator is typing.
RapidPreferredDataTypeItem[] GetPreferredDataTypes(string task, string instruction, string parameter);

// Gets the routine the controller finds called at a position of a module (synchronous)
RapidRoutineInfo GetRoutine(string task, string module, int row, int column);

// Gets the arguments of the routine call found at a position of a module (synchronous)
RapidRoutineArgument[] GetRoutineArguments(string task, string module, int row, int column, int? mark = null, int? limit = null);
```

Every method also exists in an asynchronous version, with the same name followed by `Async` and an optional `CancellationToken`.

**Members of Rws.Data.RapidModuleSymbol**
```csharp
public class RapidModuleSymbol {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidModuleSymbol" data-throw-if-not-resolved="false"></xref> class
    public RapidModuleSymbol()

    // Name of the type of the symbol, for example "robtarget"
    public string DataType { get; set; }

    // Number of array dimensions of the symbol, null when the controller did not report it
    public int? Dimensions { get; set; }

    // Whether the symbol is allocated on the heap, null when the controller did not report it
    public bool? Heap { get; set; }

    // Whether the declaration is complete, null when the controller did not report it
    public bool? Linked { get; set; }

    // Whether the symbol is local to its module, null when the controller did not report it
    public bool? Local { get; set; }

    // Name of the declared symbol
    public string Name { get; set; }

    // How many times the symbol is referred to, null when the controller did not report it
    public int? ReferenceCount { get; set; }

    // How the controller stores the symbol, null when it did not report it
    public int? Storage { get; set; }

    // What kind of symbol was declared
    public RapidSymbolType SymbolType { get; set; }

    // Path of the symbol, which the symbol resources take
    public string SymbolUrl { get; set; }

    // Returns a string representation of this declaration
    public override string ToString()

    // Path of the type of the symbol
    public string TypeUrl { get; set; }

    // Version the controller stamps on the declaration
    public string Version { get; set; }
}
```

**Members of Rws.Data.RapidRoutineInfo**
```csharp
public class RapidRoutineInfo {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidRoutineInfo" data-throw-if-not-resolved="false"></xref> class
    public RapidRoutineInfo()

    // Whether the routine is local to its module, null when the controller did not report it
    public bool? Local { get; set; }

    // Name of the routine
    public string Name { get; set; }

    // Whether the routine is named, null when the controller did not report it
    public bool? Named { get; set; }

    // Number of parameters the routine takes, null when the controller did not report it.
    // 
    // <p>The controller reports -1 when the parameter list is not linked yet.</p>
    public int? ParameterCount { get; set; }

    // Whether the routine is a procedure, a function or a trap
    public RapidSymbolType SymbolType { get; set; }

    // Path of the routine, which the program pointer resources take
    public string SymbolUrl { get; set; }

    // Returns a string representation of this routine
    public override string ToString()
}
```

**Members of Rws.Data.RapidRoutineArgument**
```csharp
public class RapidRoutineArgument {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidRoutineArgument" data-throw-if-not-resolved="false"></xref> class
    public RapidRoutineArgument()

    // Which alternative of the parameter this argument fills, null when the controller did not report it
    public int? AlternateArgument { get; set; }

    // Type of the argument, for example "num"
    public string DataType { get; set; }

    // Column the argument ends at, null when the controller did not report it
    public int? EndColumn { get; set; }

    // Line the argument ends at, null when the controller did not report it
    public int? EndRow { get; set; }

    // Length of the argument list, null when the controller did not report it
    public int? ListLength { get; set; }

    // Position of the argument in the argument list, null when the controller did not report it
    public int? ListNumber { get; set; }

    // What the argument is, for example a required argument or a name reference
    public string ObjectType { get; set; }

    // Position of the argument in the call, counted from 0
    public int? ParameterNumber { get; set; }

    // Column the argument starts at, null when the controller did not report it
    public int? StartColumn { get; set; }

    // Line the argument starts at, null when the controller did not report it
    public int? StartRow { get; set; }

    // Returns a string representation of this argument
    public override string ToString()
}
```

**Members of Rws.Data.RapidInstructionTemplate**
```csharp
public class RapidInstructionTemplate {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidInstructionTemplate" data-throw-if-not-resolved="false"></xref> class
    public RapidInstructionTemplate()

    // Number of arguments the controller reported, null when it did not report it
    public int? ArgumentCount { get; set; }

    // The suggested arguments
    public RapidInstructionTemplateArgument[] Arguments { get; set; }

    // Whether every argument has been reported, null when the controller did not report it
    public bool? Complete { get; set; }

    // Index the controller started reporting from, null when it did not report it
    public int? Mark { get; set; }

    // Argument the controller suggests selecting first, null when it did not report it
    public int? SelectedParameter { get; set; }

    // Returns a string representation of this template
    public override string ToString()

    // Version the controller stamps on the template
    public string Version { get; set; }
}
```

**Members of Rws.Data.RapidInstructionTemplateArgument**
```csharp
public class RapidInstructionTemplateArgument {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidInstructionTemplateArgument" data-throw-if-not-resolved="false"></xref> class
    public RapidInstructionTemplateArgument()

    // Position of the argument, null when the controller did not report it
    public int? ArgumentNumber { get; set; }

    // Type of the argument, for example "robtarget"
    public string DataType { get; set; }

    // Whether inserting the instruction also needs a declaration to be created for this argument,
    // null when the controller did not report it
    public bool? DeclarationNeeded { get; set; }

    // Number of array dimensions of the argument, null when the controller did not report it
    public int? Dimensions { get; set; }

    // Whether the suggested symbol is local to its module, null when the controller did not report it
    public bool? Local { get; set; }

    // Name of the argument, for example "ToPoint"
    public string Name { get; set; }

    // How the suggested symbol is declared, for example "CONST" or "TASK PERS"
    public string ObjectType { get; set; }

    // Whether the argument has to be given, null when the controller did not report it
    public bool? Required { get; set; }

    // Name of the symbol the argument refers to, empty when the argument is written as a literal
    public string Symbol { get; set; }

    // Returns a string representation of this argument
    public override string ToString()

    // Value the argument is suggested with, written the way RAPID writes it
    public string Value { get; set; }
}
```

**Members of Rws.Data.RapidObjectChild**
```csharp
public class RapidObjectChild {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidObjectChild" data-throw-if-not-resolved="false"></xref> class
    public RapidObjectChild()

    // Returns the span of one part by its name, null when the controller did not report it
    public RapidTextRange GetRange(string name)

    // What the object is, for example "module"
    public string ObjectType { get; set; }

    // Number of parts the controller reported
    public int RangeCount { get; }

    // The parts of the object, including the ones it does not hold, whose span is then empty
    public RapidObjectChildRange[] Ranges { get; set; }

    // Returns a string representation of this object
    public override string ToString()
}
```

**Members of Rws.Data.RapidObjectChildRange**
```csharp
public class RapidObjectChildRange {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidObjectChildRange" data-throw-if-not-resolved="false"></xref> class
    public RapidObjectChildRange()

    // Whether the controller reported a real span for the part, which it does not when the object
    // does not hold it
    public bool IsPresent { get; }

    // Name of the part as the controller worded it, for example "data-decl" or "endmod"
    public string Name { get; set; }

    // Where the part sits in the source
    public RapidTextRange Range { get; set; }

    // Returns a string representation of this part
    public override string ToString()
}
```

**Members of Rws.Data.RapidObjectListExtension**
```csharp
public class RapidObjectListExtension {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidObjectListExtension" data-throw-if-not-resolved="false"></xref> class
    public RapidObjectListExtension()

    // Span of the first element of the list
    public RapidTextRange First { get; set; }

    // Span of the last element of the list
    public RapidTextRange Last { get; set; }

    // Span of the whole list
    public RapidTextRange List { get; set; }

    // Returns a string representation of this extension
    public override string ToString()
}
```

**Members of Rws.Data.RapidObjectListType**
```csharp
public enum RapidObjectListType {
    // The attributes it declares
    Attributes = 8

    // The statements of its BACKWARD handler
    BackwardStatements = 1

    // The data declarations it holds
    DataDeclarations = 5

    // The statements of its ERROR handler
    ErrorStatements = 2

    // The parameter declarations it holds
    ParameterDeclarations = 6

    // The routine declarations it holds
    RoutineDeclarations = 7

    // The statements of the object
    Statements = 0

    // The type declarations it holds
    TypeDeclarations = 4

    // The statements of its UNDO handler
    UndoStatements = 3
}
```

**Members of Rws.Data.RapidPalletHeadItem**
```csharp
public class RapidPalletHeadItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidPalletHeadItem" data-throw-if-not-resolved="false"></xref> class
    public RapidPalletHeadItem()

    // Name of the category, for example "Motion&amp;Proc."
    public string Name { get; set; }

    // Number identifying the category, null when the controller did not report it
    public int? Number { get; set; }

    // Returns a string representation of this category
    public override string ToString()
}
```

**Members of Rws.Data.RapidPalletItem**
```csharp
public class RapidPalletItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidPalletItem" data-throw-if-not-resolved="false"></xref> class
    public RapidPalletItem()

    // Alternative of the parameter the entry preselects, null when the controller did not report it
    public int? Alternative { get; set; }

    // Instruction the entry inserts
    public string Instruction { get; set; }

    // Whether the entry is a language keyword rather than an instruction, null when the controller
    // did not report it
    public int? Keyword { get; set; }

    // Name shown for the entry, for example "MoveJ"
    public string Name { get; set; }

    // Parameter the entry preselects, null when the controller did not report it
    public int? Parameter { get; set; }

    // Returns a string representation of this entry
    public override string ToString()
}
```

**Members of Rws.Data.RapidPreferredDataTypeItem**
```csharp
public class RapidPreferredDataTypeItem {
    // Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidPreferredDataTypeItem" data-throw-if-not-resolved="false"></xref> class
    public RapidPreferredDataTypeItem()

    // Data type of the suggestion
    public string DataType { get; set; }

    // Name of the suggestion, for example "signaldi"
    public string Name { get; set; }

    // Returns a string representation of this suggestion
    public override string ToString()
}
```

## What is not on this page

The values the modules declare are read and written from [RAPID variables & symbols](/abb/documentation/rws-rapid-symbols). Starting the program, moving the program pointer and loading one module are on [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks). Uploading a module file to the controller, and downloading a saved one, are on [File system](/abb/documentation/rws-files).

## Try it in the demo application

The **RAPID (RWS)** page of the [demo application](/abb/documentation/demo-app) exercises these calls against a live controller, without writing any code. It is shown in [RAPID tasks & program execution](/abb/documentation/rws-rapid-tasks).