2011-05-14 17 views
6

Soy buscar la firma derecha de un método que toma una función func y un argumento arg , los copia en la red a un ordenador remoto y devuelve el resultado. Actualmente la firma tiene el siguiente aspecto:Serializable y AnyVal

def invokeRemote[A,B](address: String, func: A => B, arg: A): B 

El problema con esto es que el método produce una excepción NotSerializable si los argumentos no son Serializable o uno de los tipos primitivos de Java.

me ocurrió con la solución siguiente para encontrar este error en tiempo de compilación ...

type Func = (A => B) with Serializable 

def invokeRemote[A <: Serializable, B <: Serializable](address: String, func: Func, arg: A): B 

... pero ahora ya no es posible pasar argumentos de tipo AnyVal como Int , Flotante o Doble que no implemente explícitamente Serializable.

¿Cómo debería ser la firma del método de modo que acepte solo objetos serializables u objetos de tipo AnyVal como argumento?

Respuesta

9

Puede utilizar un context bound implícito con un rasgo personalizado y proporcionar conversiones implícitas para AnyVal y Serializable a ese rasgo.

trait Ser[M] 

implicit def toSer1[T <: AnyVal]: Ser[T] = new Ser[T] {} 
implicit def toSer2[T <: java.io.Serializable]: Ser[T] = new Ser[T] {} 

def f[T: Ser](a:T): T = a 
f(1) 
// res2: Int = 1 
f("123") 
// res3: java.lang.String = 123 
f(new Object) 
// could not find implicit value for evidence parameter of type Ser[java.lang.Object] 

El compilador buscará un parámetro implícito basado en el tipo y debido a que algunos se proporcionan para T <: AnyVal y T <: java.io.Serializable se compilará en ese caso.

Puede pegar las definiciones implícitas en el objeto complementario para Ser para que estén disponibles donde sea necesario.

Entonces, su firma se convierte en:

def invokeRemote[A:Ser, B:Ser](address: String, func: A => B, arg: A): B 
+0

Guau, gracias por esta muy buena solución.Es increíble ver de qué es capaz el compilador de Scala :) – gruenewa

1

Usando Serializable como tipo de argumento no funciona en la práctica, porque se puede tener instancias Serializable que no son de hecho serializable:

class NotSerializable(val s: String) 

// ArrayList inherits Serializable 
val list = new java.util.ArrayList[NotSerializable]() 

list.add(new NotSerializable("test")) 

// will fail at run time 
serialize(list) 

Por otra parte, Los rasgos de la colección Scala no heredan Serializable (las implementaciones sí).

def f(s: Serializable) { println(s) } 

// will fail to compile, because interface List does not inherit Serializable 
f(List("a", "b")) 

// will print true because list implementation is Serializable 
println(List("a", "b").isInstanceOf[Serializable]) 

Ser Serializable es una propiedad de tiempo de ejecución y no pueden hacerse cumplir por sí solo tipo. El uso de Serializable como tipo de argumento no lo salvará de los errores de serialización en tiempo de ejecución. Todo lo que logrará es hacer que sus funciones sean más difíciles de llamar, como ya lo está experimentando con AnyVal (y eso es solo la punta del iceberg).

0

Esto puede sonar extraño y extraño, pero sugiero considerar pasar no binarios de Java como código, pero, por ejemplo, código de JavaScript (tal vez en su forma de coffescript), y usar Rhino en el lado de ejecución.

Existen razones profundas para eso, como que las lambdas mecanografiadas son para el funcionamiento interno y para el intercambio sin tipo, pero todavía no hay ninguna teoría.

Cuestiones relacionadas