C# 8.0: Índices y rangos

“Home, home on the range,
Where the deer and the antelope play…”
Canción folklórica del oeste nortemericano

Ahora que ya tenemos oficialmente disponibles .NET Core 3.0 y C# 8.0, podemos con total propiedad continuar la presentación de las nuevas características del lenguaje introducidas en C# 8.0 que habíamos comenzado unos meses atrás. En esta ocasión le toca el turno a los nuevos operadores de índice y rango, que ya describió perfectamente en su blog mi buen amigo Jorge Serrano aquí.

En esencia, se trata de dos nuevos operadores de “azúcar sintáctico” (aunque no se si se debería seguir usando ese término en estos tiempos en que el azúcar parece ser el causante de todos los males de la humanidad :-)) que simplifican y hacen más legible la selección de un elemento o de un subconjunto de elementos de un array. Estos operadores se apoyan en dos nuevos tipos añadidos a .NET Core 3.0, System.Index y System.Range.

El operador unario ^ permite hacer referencia a un elemento contando a partir del final. Por ejemplo, en el siguiente código la función IsPalindromic permite determinar si un array es palindrómico (o sea, que se lee igualmente de atrás hacia delante que de delante hacia atrás):

using System;

namespace IndexRange
{
   class Program
   {
      static int[] data = { 1, 2, 7 /* 3 */, 4, 5, 4, 3, 2, 1 };

      static bool IsPalindromic(T[] array) where T: IComparable
      {
         for (int i = 1; i <= array.Length / 2; i++)
            if (array[i - 1].CompareTo(array[^i]) != 0)
               return false;
         return true;
      }

      static void Main(string[] args)
      {
         Console.WriteLine(IsPalindromic(data));
      }
   }
}

Observe que ^0 apunta al final del array (o sea, la posición inmediatamente detrás del último elemento); el índice correspondiente al último elemento (el primero desde atrás) es ^1. Lo cierto es que yo aún ando buscando un buen ejemplo de uso de esta nueva característica; no creo que vaya a usarla mucho en el futuro.

Lo que sí me gustó desde que los vi fueron los rangos, y los vi por primera vez cuando aparecieron en Swift, el lenguaje de Apple. Tanto me gustaron que decidí clonar el repositorio de código de Roslyn e implementar la característica yo mismo, en parte siguiendo las orientaciones en la página de Github asociada; un ejercicio altamente productivo que recomiendo a todo el que esté realmente interesado en las interioridades de un compilador moderno.

El operador de rango .. es un operador binario infijo, que produce un valor de tipo System.Range a partir de dos System.Index, aunque ambos operandos pueden ser opcionales; los ejemplos de código a continuación ilustran los diferentes escenarios . Este operador hace posible referirse mediante una sintaxis intuitiva a un subconjunto de los elementos de un array.

      // ...

      static void Print(T[] array)
      {
         foreach (var t in array)
            Console.Write($"{t} ");
         Console.WriteLine();
      }

      static void Main(string[] args)
      {
         // ...
         int m = 2, n = 4;
         Print(data[m..n]);
         Print(data[2..^3]); // data[Range.Create(2, Index.CreateFromEnd(3))]
         Print(data[..^3]);  // data[Range.ToEnd(Index.CreateFromEnd(3))]
         Print(data[2..]);   // data[Range.FromStart(2)]
         Print(data[..]);    // data[Range.All]
      }

La salida que produce el código anterior es:

7 4
7 4 5 4
1 2 7 4 5 4
7 4 5 4 3 2 1
1 2 7 4 5 4 3 2 1

Observe que el extremo inferior de los rangos es inclusivo, y el superior exclusivo. Eso es consistente, en los casos en que se omite el segundo operando, con la noción de que la primera posición desde atrás está precisamente más allá del final del array.


Referencia musical: Bueno, reconozco que esta vez se me ha “ido la mano” buscando una referencia musical en la que se usara el término range. Se trata de una palabra polisémica, que puede utilizarse para describir un conjunto de elementos de una misma naturaleza, pero también una sierra o cordillera de montañas; éste último significado es el que se utiliza en la canción mencionada. Mi grupo favorito, Kansas, incluyó una versión de este clásico en las pistas adicionales de su último disco, “The Prelude Implicit” (2016).

Mi agradecimiento a este simpático animalito por la inspiración:
Deer behind home

Octavio Hernandez

Desarrollador y consultor en tecnologías .NET. Microsoft C# MVP entre 2004 y 2010.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *