# How ResetInput and ResetOutput Control Instance State in GeoIP Operations

> Discover how ResetInput and ResetOutput manage Instance state in GeoIP operations. Safely reuse data containers across complex workflows without reloading source files.

- Repository: [Loyalsoldier/geoip](https://github.com/loyalsoldier/geoip)
- Tags: internals
- Published: 2026-03-06

---

**ResetInput and ResetOutput** reinitialize the `input` and `output` converter slices in the `Instance` struct to empty slices, enabling safe reuse of the data container across complex workflows like REPL mode without reloading source files.

The `loyalsoldier/geoip` library uses an `Instance` struct as the central orchestrator for geolocation lookups. Understanding how **ResetInput and ResetOutput** modify the internal state is essential for optimizing both single-run CLI commands and interactive sessions where the same dataset is queried repeatedly.

## The Instance Architecture and Converter Slices

At the core of the library, the `Instance` maintains two ordered slices that manage data flow:

- `input []InputConverter` – Converters that read source data and populate a **container**
- `output []OutputConverter` – Converters that consume the container and generate results

According to the source code in [`lib/instance.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/instance.go), the private `instance` struct is defined as:

```go
type instance struct {
    input  []InputConverter
    output []OutputConverter
}

```

These slices hold the registered converters that execute during the `Run()` pipeline.

## How ResetInput and ResetOutput Modify Instance State

Both methods simply reinitialize their respective slices to empty slices, effectively unregistering all previously added converters.

### ResetInput Implementation

Located at lines 81–83 in [`lib/instance.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/instance.go), **ResetInput** clears all input converters:

```go
func (i *instance) ResetInput() {
    i.input = make([]InputConverter, 0)
}

```

This removes all `InputConverter` registrations, allowing fresh input sources to be configured.

### ResetOutput Implementation

Located at lines 85–87 in the same file, **ResetOutput** clears all output converters:

```go
func (i *instance) ResetOutput() {
    i.output = make([]OutputConverter, 0)
}

```

This is particularly critical in REPL workflows where output logic changes per query while the input data remains constant.

## Impact on Workflow Patterns

The state impact varies significantly between single-run operations and interactive REPL modes.

### Single-Run Operations (No Reset Required)

For one-off commands like `geoip lookup <ip>`, the workflow creates a fresh `Instance`:

1. Call `lib.NewInstance()` (slices are initialized empty)
2. Register one input converter via `AddInput()`
3. Register one output converter via `AddOutput()`
4. Execute `Run()`, which calls `RunInput()` then `RunOutput()`

Since the instance is newly created, its slices are already empty, making reset calls unnecessary.

### REPL Mode (ResetOutput Required)

In interactive lookup mode, the same `Instance` and container are reused across multiple searches. As implemented in [`lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/lookup.go) (lines 127–129), the pattern is:

```go
instance, _ := lib.NewInstance()
instance.AddInput(getInputForLookup(...))   // Register input once

container := lib.NewContainer()
instance.RunInput(container)              // Populate container once

for each search {
    instance.ResetOutput()                 // Clear previous output logic
    instance.AddOutput(getOutputForLookup(search, ...))
    instance.RunOutput(container)          // Reuse existing container
}

```

**State impact during REPL:**
- The `input` slice remains constant (holding the original file reader)
- The `output` slice is cleared and repopulated for each iteration
- The **container** retains parsed data, avoiding expensive reloads

### Switching Data Sources (Both Resets Required)

When changing input files or formats entirely, both slices must be cleared:

```go
inst.ResetInput()
inst.ResetOutput()
inst.AddInput(newSource)
inst.AddOutput(newFormat)
inst.Run()

```

This pattern discards both the old input pipeline and any accumulated output configurations.

## Practical Implementation Examples

### Example 1: Simple One-Off Lookup

For single IP lookups where the instance is discarded afterward, no reset calls are needed:

```go
inst, _ := lib.NewInstance()
inst.AddInput(getInputForLookup("text", "true", uri, ""))   // Load list file
inst.AddOutput(getOutputForLookup("1.2.3.4"))             // Search IP
inst.Run() // Executes input → output pipeline once

```

### Example 2: Interactive REPL with ResetOutput

This pattern from [`lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/lookup.go) demonstrates efficient reuse of the loaded dataset:

```go
inst, _ := lib.NewInstance()
inst.AddInput(getInputForLookup("text", "true", uri, ""))

c := lib.NewContainer()
inst.RunInput(c) // Load the list only once

for {
    fmt.Print("Enter IP (or \"exit\"): ")
    var ip string
    fmt.Scanln(&ip)
    if ip == "exit" { break }

    // Clear previous output logic, then set fresh one for new query
    inst.ResetOutput()
    inst.AddOutput(getOutputForLookup(ip))
    inst.RunOutput(c) // Reuse the same container
}

```

### Example 3: Switching Input and Output Sources

When migrating between different file formats or databases, reset both slices:

```go
inst, _ := lib.NewInstance()

// First operation using CSV source
inst.AddInput(csvInput)
inst.AddOutput(csvOutput)
inst.Run()

// Switch to MMDB source
inst.ResetInput()
inst.ResetOutput()
inst.AddInput(mmdbInput)
inst.AddOutput(mmdbOutput)
inst.Run()

```

## Summary

- **ResetInput** (lines 81–83 in [`lib/instance.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/instance.go)) reinitializes the `input` slice to empty, removing all `InputConverter` registrations
- **ResetOutput** (lines 85–87 in [`lib/instance.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/instance.go)) reinitializes the `output` slice to empty, removing all `OutputConverter` registrations
- In REPL workflows ([`lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/lookup.go) lines 127–129), **ResetOutput** enables query-specific output logic while preserving the loaded container data
- Single-run operations do not require resets because `NewInstance()` initializes empty slices
- Resetting both slices allows complete reconfiguration of the Instance for different data sources or output formats

## Frequently Asked Questions

### What is the difference between ResetInput and ResetOutput?

**ResetInput** clears the slice holding `InputConverter` implementations that read source data into the container, while **ResetOutput** clears the slice holding `OutputConverter` implementations that format and return results. According to [`lib/instance.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/instance.go), both simply reinitialize their respective slices to empty arrays using `make([]Type, 0)`.

### When should I use ResetOutput instead of creating a new Instance?

Use **ResetOutput** in interactive or batch scenarios where the input dataset remains constant but output requirements change per query. As shown in [`lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/lookup.go), this avoids the expensive overhead of reloading large IP lists into the container via `RunInput()` for every operation.

### Does ResetInput clear the container data?

No. **ResetInput** only unregisters the converter functions; it does not modify the **container** that stores parsed data. The container is passed explicitly to `RunInput()` and `RunOutput()` and persists independently until garbage collected or explicitly overwritten.

### How do these methods affect performance in REPL mode?

**ResetOutput** significantly improves REPL performance by allowing the same `Container` instance—populated once via `RunInput()`—to be reused across hundreds of lookups. Without this method, you would need to either create new `Instance` objects (wasting memory) or accumulate output converters (causing logical errors), as the source code in [`lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/lookup.go) demonstrates by calling `ResetOutput()` at the start of each loop iteration.