trabajo tesis temas sobre sindrome proyecto mexico investigacion down doctorales antecedentes scala memory-management

tesis - En estos casos, la clase de valor de Scala estará "enmarcada", ¿verdad?



trabajo de investigacion sobre sindrome de down (3)

En los tres casos, no habrá boxeo en absoluto.

Es bastante fácil de verificar por ti mismo:

class ActionId(val value: Int) extends AnyVal object Foo { def someFunction(): ActionId = { new ActionId(123) } }

Ahora ejecutemos scalac, y tendremos un grupo de archivos de clase (archivos con bytecode). El que necesitamos es Foo / $.

» javap Foo/$ Compiled from "Boxing.scala" public final class Foo$ extends java.lang.Object{ public static final Foo$ MODULE$; public static {}; public int someFunction(); }

Como puede ver, incluso si la clase de valor se fuga de la función, generalmente no estaría encuadrada.

case class Post(id: ActionId, notion: String) object Foo2 { def someFunction(): Post = { Post(new ActionId(123), "So ActionID will be boxed?") } }

scalac => javap:

» javap Post Compiled from "Boxing.scala" public class Post extends java.lang.Object implements scala.Product,scala.Serializable{ public static scala.Function1 tupled(); public static scala.Function1 curried(); public int id(); public java.lang.String notion(); public Post copy(int, java.lang.String); public int copy$default$1(); public java.lang.String copy$default$2(); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public Post(int, java.lang.String); }

Como puede ver, la identificación aquí representada como simple int (por ejemplo, tercer método).

Finalmente, ¿valorará la clase encuadrada si el objeto con un miembro de clase de valor no se devuelve (realmente no escapa al alcance)?

case class Post(id: ActionId, notion: String) object Foo3 { def anotherFunction(): Unit { val post = Post(new ActionId(123), "Will be boxed?") } }

Si observamos de cerca el bytecode del método, esto es lo que veremos:

Code: Stack=4, Locals=2, Args_size=1 0: new #15; //class Post 3: dup 4: bipush 123 6: ldc #17; //String Will be boxed? 8: invokespecial #20; //Method Post."<init>":(ILjava/lang/String;)V 11: astore_1 12: return LocalVariableTable: Start Length Slot Name Signature 0 13 0 this LFoo3$; 12 0 1 post LPost;

No hay boxeo de int en ActionId. Si fuera una caja, verías algo como esto:

Code: Stack=5, Locals=2, Args_size=1 0: new #15; //class Post 3: dup 4: new #17; //class ActionId 7: dup 8: bipush 123 10: invokespecial #20; //Method ActionId."<init>":(I)V 13: ldc #22; //String Will be boxed? 15: invokespecial #25; //Method Post."<init>":(LActionId;Ljava/lang/String;)V 18: astore_1 19: return LocalVariableTable: Start Length Slot Name Signature 0 20 0 this LFoo3$; 19 0 1 post LPost;

Usted ve, la diferencia es bipush 123 versus

4: new #17; //class ActionId 7: dup 8: bipush 123 10: invokespecial #20; //Method ActionId."<init>":(I)V

Si tengo esta clase de valor:

class ActionId(val value: Int) extends AnyVal

Entonces, en todos los ejemplos a continuación, ¿se asignará un objeto para la clase de valor? (Estará "en caja"; no se desenvolverá simplemente en un número entero de 32 bits, ¿verdad?)

  1. Una función que devuelve una clase de valor: ¿la clase de valor escapa del alcance y, por lo tanto, estará "encuadrada"?

    def someFunction(): ActionId = { ... return ActionId(123) }

  2. Una función que devuelve un objeto con un miembro de clase de valor : ¿la clase de valor escapa del alcance y, por lo tanto, estará "encuadrada"?

    case class Post(id: ActionId, ...) { ... } def someFunction(): Post = { ... val somePost = Post(ActionId(123), ...) // ActionId will be "boxed", right? return somePost }

  3. Incluso si el objeto con un miembro de la clase de valor no se devuelve (realmente no escapa al alcance), la clase de valor seguirá siendo "encuadrada", cuando se use como miembro de otra clase (como un campo en la clase Post , en este ejemplo)?

    def anotherFunction() { ... val somePost = Post(ActionId(123), ...) // "Boxed" here too, right? // ... do something with somePost // But don''t: return somePost // However some *other* similar functions *do* return `somePost` — so // class `Post` must be able to box the ActionId? Hence it''s boxed (above)? }

Relacionado con esto está esta respuesta , que dice que cuando la clase de valor no escapa del alcance , está efectivamente en línea. Se refiere al documento SIP-15 del Proceso de Mejora de Scala para más detalles. Sin embargo, en lo que puedo decir, SIP-15 en realidad no menciona que una instancia de clase de valor que escapa del alcance se "encasillará". Pero creo que parece razonable que tendría que estar "en caja". (¿Por qué el SIP no declara explícitamente que será encuadrado si escapa?)


Ninguno de sus ejemplos resulta en boxeo. Las clases de valor solo se empaquetan con genéricos, con matrices, y cuando se escriben como una superclase / rasgo (por ejemplo, Any / AnyVal)

Están encerrados en cajas con genéricos porque de lo contrario no puedes distinguirlos del valor (y los primitivos necesitan una caja de todos modos). El mismo trato con Cualquiera, y otras superclases / rasgos necesitan una caja o la relación tipo es incorrecta.

Están encuadrados con matrices porque las matrices necesitan saber el tipo de contenido, pero la JVM no entiende el concepto de "tipo de valor". Así que terminarías con una matriz que decía que era el tipo de caja, pero Scala pretendía que era una matriz del tipo de valor; se tomó una decisión (basada en problemas anteriores con Array cuando no era solo una matriz Java / JVM simple) que esto llevaría a demasiados errores sutiles y casos de esquina.

Aquí hay un ejemplo de las tres formas de obtener el boxeo:

trait Q extends Any {} class X(val x: String) extends AnyVal with Q {} // Array val a = Array(new X("salmon")) // boxed // Generic val b = Option(new X("minnow")) // boxed // Upcast val c = (new X("perch"): Any) // boxed val d = (new X("cod"): AnyVal) // boxed val e = (new X("herring"): Q) // boxed

Todo lo demás, pasando por varias funciones, etc., no requiere boxeo, incluidos todos tus ejemplos.

Las matrices son un caso especial porque puedes almacenar las primitivas y sacarlas de nuevo como clases de valor con sobrecarga de código de bytes cero, pero con mucha carga sintáctica:

class Y(val repr: String) extends AnyVal {} val y1 = new Y("apple") // unboxed val y2 = new Y("orange") // unboxed val ys: Array[String] = Array(y1.repr, y2.repr) // no overhead val y3 = new Y(ys(0)) // no overhead


Con algunos moldes implícitos, en realidad es posible sortear el problema de matriz sin la sintaxis requerida por rex-kerr. Lo utilicé junto con ¿Cómo reducir la cantidad de objetos creados en Scala?

Y.scala:

import scala.language.implicitConversions class Y(val repr: String) extends AnyVal {} object Y { implicit def stringToY (v:String) = new Y(v) implicit def yToString (v:Y) = v.repr }

Archivo principal:

import Y._ val y1 = new Y("apple") // unboxed val y2 = new Y("orange") // unboxed val ys: Array[String] = Array(y1, y2) // Implicit cast val y3:Y = ys(0)