¿Qué significa el operador `#` en Scala?

131

Veo este código en este blog: Programación de nivel de tipo en Scala :

// define the abstract types and bounds
trait Recurse {
  type Next <: Recurse
  // this is the recursive function definition
  type X[R <: Recurse] <: Int
}
// implementation
trait RecurseA extends Recurse {
  type Next = RecurseA
  // this is the implementation
  type X[R <: Recurse] = R#X[R#Next]
}
object Recurse {
  // infinite loop
  type C = RecurseA#X[RecurseA]
}

Hay un operador #en el código R#X[R#Next]que nunca he visto. Dado que es difícil buscarlo (ignorado por los motores de búsqueda), ¿quién puede decirme qué significa?

Viento libre
fuente
1
el "signo de libra" a veces se denomina "octathrop" (esa búsqueda de google me trajo a esta página).
philwalk
3
Haga ese octothorpe o octothorp
smparkes
¿Qué hay de otros operadores como # + y # - (ver github.com/tpolecat/doobie/blob/series/0.4.x/yax/h2/src/main/… )? ¿Hay una lista completa?
Markus Barthlen

Respuestas:

240

Para explicarlo, primero tenemos que explicar las clases anidadas en Scala. Considere este simple ejemplo:

class A {
  class B

  def f(b: B) = println("Got my B!")
}

Ahora intentemos algo con eso:

scala> val a1 = new A
a1: A = A@2fa8ecf4

scala> val a2 = new A
a2: A = A@4bed4c8

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

Cuando declaras una clase dentro de otra clase en Scala, estás diciendo que cada instancia de esa clase tiene dicha subclase. En otras palabras, no hay A.Bclase, pero hay a1.By a2.Bclases, y son diferentes clases, como el mensaje de error nos dice más arriba.

Si no entendió eso, busque los tipos dependientes de la ruta.

Ahora, #le permite referirse a tales clases anidadas sin restringirlo a una instancia particular. En otras palabras, no hay A.B, pero hay A#B, lo que significa una Bclase anidada de cualquier instancia de A.

Podemos ver esto en el trabajo cambiando el código anterior:

class A {
  class B

  def f(b: B) = println("Got my B!")
  def g(b: A#B) = println("Got a B.")
}

Y probándolo:

scala> val a1 = new A
a1: A = A@1497b7b1

scala> val a2 = new A
a2: A = A@2607c28c

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

scala> a2.g(new a1.B)
Got a B.
Daniel C. Sobral
fuente
Excelente ejemplo Acepto totalmente que funciona de esa manera, pero es difícil de entender esto: scala> classOf [A # B] res7: Clase [A # B] = clase A $ B scala> classOf [aB] res8: Clase [aB] = clase A $ B. lo que significa que tienen el mismo tipo en realidad?
Chiron
2
Sus valores tienen la misma representación de cadena, e incluso pueden ser iguales. Classes una representación en tiempo de ejecución de las clases de Java, y está limitada incluso en Java. Por ejemplo, List<String>y List<Integer>tener el mismo tiempo de ejecución Class. Si Classno es lo suficientemente rico como para representar tipos de Java , es casi inútil cuando se representan tipos de Scala . Una vez más, a la res7: Class[A#B] = class A$Bizquierda del signo igual es un tipo, a la derecha del tipo igual si un valor que es la representación en tiempo de ejecución Java de una clase.
Daniel C. Sobral
13

Se conoce como proyección de tipo y se usa para acceder a los miembros de tipo.

scala> trait R {
     |   type A = Int
     | }
defined trait R

scala> val x = null.asInstanceOf[R#A]
x: Int = 0
missingfaktor
fuente
66
Esta es una no respuesta. Básicamente muestra el mismo código que la pregunta, solo un poco más corto. ¿Cuál es, por ejemplo, la diferencia de notación de puntos? ¿Dónde usaría este # en código real?
notan3xit
2
@ notan3xit tal vez sea una no respuesta a lo que querías preguntar. Pero lo que preguntaste es "... que nunca he visto. Dado que es difícil buscarlo (ignorado por los motores de búsqueda), ¿quién puede decirme qué significa?"
nafg