Indexer (programming)

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search

In object-oriented programming, an indexer allows instances of a particular class or struct to be indexed just like arrays.[1] It is a form of operator overloading.

Implementations

[edit | edit source]

In C++ one can emulate indexing by overloading the [] operator. The expression a[b...] translates to a call to the user-defined function operator[] as (a).operator[](b...).[2] Here is an example,

struct vector {
    int size; double* data;
    vector(int n) { size = n; data = new double[n](); }
    ~vector(){ size = 0; delete[] data; }
    double& operator[](int i) { return data[i]; }
};

#include <iostream>

int main() {
    vector v(3);
    for (int i = 0; i < v.size; i++) v[i] = i + 1;
    for (int i = 0; i < v.size; i++) std::cout << v[i] << "\n";
    return 0;
}

Indexers are implemented through the get and set accessors for the operator[]. They are similar to properties, but differ by not being static, and the fact that indexers' accessors take parameters. The get and set accessors are called as methods using the parameter list of the indexer declaration, but the set accessor still has the implicit value parameter.

Example 1

[edit | edit source]
public class Vector
{
    private double[] _data;

    public Vector(int n)
    {
        _data = new double[n];
    }

    public int Size => _data.Length;

    public double this[int i]
    {
        get => _data[i];
        set => _data[i] = value;
    }

    public static void Main()
    {
        var vector = new Vector(3);
        for (var i = 0; i < vector.Size; i++)
            vector[i] = i + 1;
        for (var i = 0; i < vector.Size; i++)
            System.Console.WriteLine(vector[i]);
    }
}

Example 2

[edit | edit source]

Here is a C# example of the usage of an indexer in a class: [3]

class Family
{
    private List<string> _familyMembers = new List<string>();

	public Family(params string[] members)
	{
	    _familyMembers.AddRange(members);
	}

	public string this[int index]
	{
		// The get accessor
		get => _familyMembers[index];

		// The set accessor with 
		set => _familyMembers[index] = value;
	}

	public int this[string val]
	{
		// Getting index by value (first element found)
		get => _familyMembers.FindIndex(m => m == val);
	}

	public int Length => _familyMembers.Count;
}

Usage example:

void Main()
{
    var doeFamily = new Family("John", "Jane");
    for (int i = 0; i < doeFamily.Length; i++)
    {
        var member = doeFamily[i];
        var index = doeFamily[member]; // same as i in this case, but it demonstrates indexer overloading allowing to search doeFamily by value.
        Console.WriteLine($"{member} is the member number {index} of the {nameof(doeFamily)}");
    }
}

In this example, the indexer is used to get the value at the nth position, and then to get the position in the list referenced by its value. The output of the code is:

John is the member number 0 of the doeFamily
Jane is the member number 1 of the doeFamily

In PHP indexing can be implemented via the predefined ArrayAccess interface,[4]

class Vector implements ArrayAccess
{
    function __construct(int $n) {
        $this->size = $n;
        $this->data = array_fill(0, $n, 0);
    }

    public function offsetGet($offset): mixed {
        return $this->data[$offset];
    }

    public function offsetSet($offset, $value): void {
        $this->data[$offset] = $value;
    }

    public function offsetExists($offset): bool {}

    public function offsetUnset($offset): void {}
}

$vector = new Vector(3);

for ($i = 0; $i < $vector->size; $i++) $vector[$i] = $i + 1;
for ($i = 0; $i < $vector->size; $i++) print "{$vector[$i]}\n";

Python

[edit | edit source]

In Python one implements indexing by overloading the __getitem__ and __setitem__ methods,

import array

class Vector(object):
    def __init__(self, n: int):
        self.size = n
        self.data = array.array("d", [0.0] * n)

    def __getitem__(self, i: int):
        return self.data[i]

    def __setitem__(self, i: int, value):
        self.data[i] = value

vector = Vector(3)
for i in range(vector.size):
    vector[i] = i + 1
for i in range(vector.size):
    print(vector[i])

Rust provides the std::ops::Index trait.[5]

use std::ops::Index;

enum Nucleotide {
    A,
    C,
    G,
    T,
}

struct NucleotideCount {
    a: usize,
    c: usize,
    g: usize,
    t: usize,
}

impl Index<Nucleotide> for NucleotideCount {
    type Output = usize;

    fn index(&self, nucleotide: Nucleotide) -> &Self::Output {
        match nucleotide {
            Nucleotide::A => &self.a,
            Nucleotide::C => &self.c,
            Nucleotide::G => &self.g,
            Nucleotide::T => &self.t,
        }
    }
}

let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12};
assert_eq!(nucleotide_count[Nucleotide::A], 14);
assert_eq!(nucleotide_count[Nucleotide::C], 9);
assert_eq!(nucleotide_count[Nucleotide::G], 10);
assert_eq!(nucleotide_count[Nucleotide::T], 12);

Smalltalk

[edit | edit source]

In Smalltalk one can emulate indexing by (e.g.) defining the get: and set:value: instance methods. For example, in GNU Smalltalk,

Object subclass: vector [ |data| ]
vector class extend [ new: n [ |v| v:=super new. v init: n. ^v] ]
vector extend [ init: n [ data:= Array new: n ] ]
vector extend [ size [ ^(data size) ] ]
vector extend [ get: i [ ^(data at: i) ] ]
vector extend [ set: i value: x [ data at: i put: x ] ]
v:=vector new: 3
1 to: (v size) do: [:i| v set: i value: (i+1) ]
1 to: (v size) do: [:i| (v get: i) printNl ]

See also

[edit | edit source]

Lua error in mw.title.lua at line 392: bad argument #2 to 'title.new' (unrecognized namespace name 'Portal').

References

[edit | edit source]
  1. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  2. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  3. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  4. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
  5. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).