valor referencia por paso parametros pointers types nimrod nim

pointers - paso - parametros por valor y referencia php



¿Cuál es el modelo de valor vs. referencia en Nimrod? (2)

NOTA: No estoy preguntando acerca de la diferencia entre puntero y referencia, y para esta pregunta es completamente irrelevante.

Una cosa que no pude encontrar explícitamente: ¿qué modelo usa Nimrod?

Como C ++, donde tiene valores y con los new , crea punteros a datos (en tal caso, la variable podría mantener el puntero a un puntero a un puntero a ... a datos).

¿O como C #, donde tiene tipos de POD como valores, pero los objetos definidos por el usuario con referencia (implícitamente)?

Descubrí que solo la desreferenciación es automática, como en Go.

Expresar de otro modo. Usted define su nuevo tipo, digamos Student (con nombre, universidad, dirección). Usted escribe:

var student ...?

  1. para hacer que el student mantenga datos reales (de tipo / clase de Student )
  2. Para que el student mantenga un puntero a los datos.
  3. para hacer que el student mantenga un puntero a un puntero a los datos

¿O algunos de esos puntos son imposibles?


Por defecto el modelo es de pasar datos por valor. Cuando creas una var de un tipo específico, el compilador asignará en la pila el espacio requerido para la variable. Lo que se espera, ya que Nim compila a C, y los tipos complejos son solo estructuras. Pero como en C o C ++, también puedes tener punteros. Existe la palabra clave ptr para obtener un puntero no seguro, principalmente para interactuar con el código C, y hay una ref para obtener una referencia segura recogida de basura (ambas documentadas en la sección Referencias y tipos de punteros del manual de Nim).

Sin embargo, tenga en cuenta que incluso cuando especifica un proc para pasar una variable por valor, el compilador es libre de decidir pasarlo internamente por referencia si considera que puede acelerar la ejecución y es seguro al mismo tiempo. En la práctica, la única vez que he usado referencias es cuando estaba exportando tipos Nim a C y tenía que asegurarme de que tanto C como Nim apuntaban a la misma memoria. Recuerde que siempre puede verificar el código C generado en el directorio nimcache . Verá entonces que un parámetro var en un proceso es solo un puntero a su estructura C.

Aquí hay un ejemplo de un tipo con constructores que se crearán en la pila y se pasarán por valor, y el puntero correspondiente como la versión:

type Person = object age: int name: string proc initPerson(age: int, name: string): Person = result.age = age result.name = name proc newPerson(age: int, name: string): ref Person = new(result) result.age = age result.name = name when isMainModule: var a = initPerson(3, "foo") b = newPerson(4, "bar") echo a.name & " " & $a.age echo b.name & " " & $b.age

Como puedes ver, el código es esencialmente el mismo, pero hay algunas diferencias:

  • La forma típica de diferenciar la inicialización es usar init para los tipos de valor y nuevo para los tipos de referencia. Además, tenga en cuenta que la biblioteca estándar de Nim confunde esta convención, ya que parte del código es anterior (por ejemplo, newStringOfCap no devuelve una referencia a un tipo de cadena).
  • Dependiendo de lo que realmente hagan sus constructores , la versión ref permite devolver un valor nil , que puede tratar como un error, mientras que el constructor de valores lo obliga a generar una excepción o cambiar el constructor para usar la forma var mencionada a continuación para que Puede devolver un bool indicando éxito. El fracaso tiende a ser tratado de diferentes maneras.
  • En lenguajes similares a C, hay una sintaxis explícita para acceder al valor de memoria de un puntero o al valor de memoria señalado por él (eliminación de referencias). En Nim también hay, y es la notación del subíndice vacío ( [] ). Sin embargo, el compilador intentará colocarlos automáticamente para evitar saturar el código. Por lo tanto, el ejemplo no los usa. Para probar esto puedes cambiar el código para leer:

    echo b[].name & " " & $b[].age

    Que funcionará y compilará como se espera. Pero el siguiente cambio producirá un error del compilador porque no puede eliminar la referencia a un tipo que no sea de referencia:

    echo a[].name & " " & $a[].age

  • La tendencia actual en la comunidad Nim es deshacerse de los prefijos de una sola letra para diferenciar los tipos de valor frente a los de referencia. En la convención anterior, tendría un TPerson y un alias para el valor de referencia como PPerson = ref TPerson . Puedes encontrar una gran cantidad de código aún utilizando esta convención.

  • Dependiendo de qué deben hacer exactamente su objeto y su constructor, en lugar de que un initPerson devuelva el valor, también podría tener un init(x: var Person, ...) . Pero el uso de la variable de result implícita permite que el compilador optimice esto, por lo que es mucho más una preferencia de gusto o requisitos de pasar un bool a la persona que llama.

Puede ser cualquiera.

type Student = object ...

es aproximadamente equivalente a

typedef struct { ... } Student;

en C, mientras

type Student = ref object ...

o

type Student = ptr object ...

es aproximadamente equivalente a

typedef struct { ... } *Student;

en C (con ref denota una referencia que es rastreada por el recolector de basura, mientras que ptr no es rastreada).