seguidores por partir paga millon ganar dinero cuantos cuanto como cobrar scala annotations inline

scala - por - Hacer el método realmente en línea



instagram paga como youtube (2)

Forjo un ejemplo simple para verificar el comportamiento de la anotación @inline :

import scala.annotation.tailrec object InlineTest extends App { @inline private def corec(x : Int) : Int = rec(x - 1) @tailrec private def rec(x : Int) : Int = if (x < 3) x else { if (x % 3 == 0) corec(x-1) else rec(x-4) } @tailrec private def rec1(x : Int) : Int = if (x < 3) x else { if (x % 3 == 0) { val arg = x - 1 rec1(arg - 1) } else rec1(x-4) } Console.println( rec(args(0).toInt) ) }

Este ejemplo compilado sin advertencias, ambas anotaciones de tailrec estaban en efecto como yo pensaba. Pero cuando realmente ejecuto el código, me da una excepción de stackoverflow. Esto significa que la optimización de la recursividad de la cola falló debido a que el método en línea no estaba en línea.

Tengo la función de control rec1 que difiere de la original solo con la transformación "en línea" realizada manualmente. Y como esta función funciona bien como se esperaba evitando la excepción de stackoverflow con recursividad de cola.

¿Qué impide que el método anotado esté en línea?


Esto no funcionará, de hecho. El tratamiento de @inline se aplica mucho más tarde que el tratamiento de las llamadas finales, evitando la optimización que está esperando.

Durante la llamada fase de "tailcalls" del compilador, el compilador intenta transformar los métodos para que las llamadas recursivas de cola se eliminen y se reemplacen por bucles. Tenga en cuenta que solo las llamadas dentro de la misma función se pueden eliminar de esta manera. Entonces, aquí, el compilador podrá transformar la función rec en algo más o menos equivalente a lo siguiente:

@tailrec private def rec(x0: Int) : Int = var x: Int = x0 while (true) { if (x < 3) x else { if (x % 3 == 0) return corec(x-1) else { x = x-4 continue } } }

Tenga en cuenta que la llamada a corec no se elimina, porque está llamando a otro método. En ese momento en el compilador, @inline anotaciones @inline ni siquiera se miraron.

Pero ¿por qué el compilador no te advierte que no puede eliminar la llamada, ya que has puesto @tailrec ? Porque solo comprueba que en realidad puede reemplazar todas las llamadas al método actual. No importa si otro método en el programa llama a rec (incluso si ese método, en este caso corec , se llama por rec ).

Entonces no recibes ninguna advertencia, pero aún así, el llamado a corec no es eliminado.

Cuando llegue al tratamiento de @inline más adelante en la @inline de compilación, y suponiendo que elige seguir sus consejos para corec línea, se modificará de nuevo rec para corec el cuerpo de corec , que ofrece lo siguiente:

@tailrec private def rec(x0: Int) : Int = var x: Int = x0 while (true) { if (x < 3) x else { if (x % 3 == 0) return rec((x-1) - 1) else { x = x-4 continue } } }

No importa entonces que esto crea una nueva llamada recursiva de cola. Es demasiado tarde. No será eliminado más. Por lo tanto, el desbordamiento de la pila.

Puede usar el objeto TailCalls y sus métodos para convertir métodos mutuamente recursivos en bucles. Ver detalles en la API .


Tenga en cuenta que hay una propuesta en progreso ( scala PR 567 ) para introducir una palabra clave en inline real. (Sept. 2016)

Consulte " SIP NN: Definiciones en línea y meta Expresiones (Borrador público) "

Funcionará para:

definiciones de valores concretos , por ejemplo

inline val x = 4

métodos concretos , por ejemplo

inline def square(x: Double) = x * x

parámetros de métodos en línea , por ejemplo

inline def pow(b: Double, inline n: Int): Double = { if (n == 0) 1 else pow(b, n - 1) }

Las definiciones de valor y método etiquetadas en línea son efectivamente finales; ellos no pueden ser anulados
Los miembros en línea tampoco anulan a otros miembros. En cambio, cada miembro en línea se convierte en una alternativa sobrecargada de todos los demás miembros con el mismo nombre.

Las definiciones en línea solo existen en el momento de la compilación ; no se les asigna almacenamiento en el diseño de objetos y no se genera código para ellos en tablas de métodos de objetos.
Eso significa que está bien tener un miembro en línea que tenga el mismo borrado de tipo que otro miembro con el mismo nombre.