Zig añade estabilidad de punteros a ArrayList
Zig: Pointer Stability for ArrayLists
El lenguaje Zig incorpora a std.ArrayList los candados de estabilidad de punteros que ya existían en sus contenedores HashMap. Esta técnica, aportada por Leo Emar-Kar, permite detectar en tiempo de ejecución el uso de punteros que quedan invalidados al reasignar memoria. El devlog muestra un ejemplo con un error sutil y cómo lockPointers() y unlockPointers() ayudan a encontrar el fallo. Además, se advierte de que operaciones como orderedRemove() o pop() también pueden invalidar punteros aunque no reasignen memoria.
A diferencia de HashMap y sus amigos, ArrayList está ordenado, lo que significa que las operaciones sobre la lista pueden mover elementos incluso sin mover, redimensionar o liberar la memoria subyacente de la lista en su conjunto.
- amluto
Esto parece flojo.
En un lenguaje como Rust, el compilador "bloqueará" los punteros por ti, y no puedes olvidarlo.
En un lenguaje como C++ (y presumiblemente Zig), uno podría, al menos en teoría, tener que los iteradores y slices que referencian el almacenamiento de un array dinámico mantengan algún tipo de bloqueo que fije el almacenamiento.
Pero esta API requiere que el programador recuerde bloquear los punteros y también requiere que el programador mantenga el bloqueo activo durante la región correcta del código. Y me parece que incluso el ejemplo en la publicación del blog tiene el bloqueo tomado completamente fuera de la función que requiere estabilidad, así que no hay nada que haga que el ámbito del bloqueo sea correcto. Ni siquiera el sistema de tipos puede ayudar: la función parse ofensiva no puede declarar que quiere un parámetro ArrayList con punteros bloqueados.
- _bohm
Es una buena característica, pero no puedo evitar sentir que, si necesitas un puntero estable a un elemento en una colección, ArrayList es la estructura de datos equivocada para usar. ¿Quizás alguien puede intervenir y darme un ejemplo de cuándo harías esto en lugar de, por ejemplo, simplemente almacenar un índice? Alternativamente, podrías usar una Lista Enlazada Desenrollada (antes conocida como SegmentedList en Zig antes de que fuera eliminada en 0.16, no estoy seguro de por qué).
- portly
Esto tiene mucho sentido si consideras que es consistente con el resto del lenguaje. Es una forma más de establecer trampas en tu código para atrapar tus propios errores de programación. Similar a usar asserts en tus funciones para verificar la entrada y salida.
Uso mucho ArrayList, así que estoy emocionado de agregar esto en todo el código para endurecerlo.
Puedo imaginar que esto no es del agrado de todos, pero entonces probablemente tampoco disfrutarías de ninguna de las otras explicitudes.
- Rendello
Aparte: una característica de sintaxis de Zig que realmente extrañé en Rust se muestra en el segundo bloque de código, a saber, literales de cadena multilínea con prefijo, así:
const text =
\\Esto es un comentario largo
\\Pero puedo dividirlo entre líneas arbitrariamente
\\Y mantener mi indentación.
;
He empezado a usar la biblioteca de macros de Rust `docstr` [1], que hace lo mismo:
const TEXT: &'static str = docstr!(
/// Ahora puedo hacerlo en Rust también.
/// Prefiero este estilo muchas veces
/// para textos largos.
);
Incluso funciona con macros (ejemplo de la documentación):
let greeting: String = docstr!(format!
/// Hola, mi nombre es {name}.
/// ¡Tengo {} años!
age
);
- boricj
Me tomó un minuto entender que esto verifica el cambio de puntero dentro del contenedor, en lugar de bloquear/desbloquear la estructura de datos como una superficie SDL.
Recientemente implementé un contenedor C++ personalizado para una ruta cuyos componentes podían ser iterados, respaldado por un std::string. Simplemente almaceno índices y una referencia a la cadena, de modo que mis iteradores no se invalidan si el std::string se reasigna después de ser modificado. Mucho menos propenso a errores por un costo adicional pequeño.