2011-08-24 17 views
7

me encontré con este número de Scala: https://issues.scala-lang.org/browse/SI-4939tema objeto `Foo {val 1 = 2}` en Scala

Parece que podemos definir un método cuyo nombre es un número:

scala> object Foo { val 1 = 2 } 
defined module Foo 

Pero podemos 't lo invocan:

scala> Foo.1 
<console>:1: error: ';' expected but double literal found. 
     Foo.1 

y podemos invocarlo dentro del objeto:

scala> object O { val 1 = 1; def x = 1 } 
defined module O 
scala> O.x 
res1: Int = 1 

Y siga arrojará error:

scala> object O { val 1 = 2; def x = 1 } 
defined module O 
scala> O.x 
scala.MatchError: 2 
    at O$.<init>(<console>:5) 
    at O$.<clinit>(<console>) 
    at .<init>(<console>:7) 
    at .<clinit>(<console>) 
    at RequestResult$.<init>(<console>:9) 

utilizo scalac -Xprint:typer para ver el código, la parte val 1 = 2 es:

<synthetic> private[this] val x$1: Unit = (2: Int(2) @unchecked) match { 
    case 1 =>() 
} 

A partir de ella, podemos ver el nombre del método cambió a x$1, y solo se puede invocar dentro de ese objeto.

y la resolución de esta cuestión es: No fijará

Quiero saber ¿hay alguna razón para que un número que es el nombre de un método? ¿Hay algún caso en el que necesitemos usar un método de "número"?

+0

Más discusión en la lista de correo vinculado desde el billete: https://groups.google.com/ forum/#! topic/scala-user/k57U6jt8Za0 –

Respuesta

10

No hay ningún nombre "1" que se enlaza aquí. val 1 = 2 es una expresión de coincidencia de patrones, de la misma manera que val (x,2) = (1,2) vincula x a 1 (y arrojaría un MatchError si el segundo elemento no fuera el mismo). Está permitido porque no hay una razón real para agregar un caso especial para prohibirlo; de esta forma, la coincidencia de patrones val funciona (casi) exactamente de la misma manera que match coincidencia de patrones.

+1

Eso tiene sentido, pero es extraño que se cree un 'val' con el nombre' x $ 1'. –

+0

Detalle de implementación. El caso en el que un valor vale exactamente un nombre es especial, por lo que no se obtiene un 'Tuple1' (¿eso incluso existe?), Pero el caso donde se une no recibe un valor (semi) anónimo para contener Los resultados. Pruebe 'val hd :: tl = List (1,2)' y verá que se creará un 'x $ 1' similar para contener una tupla a la que accedan los usuarios de" hd "y" tl ". En el caso '1 = 1' el" titular "es un" Tuple0 ", es decir,' Unidad'. –

+0

+1 probablemente este sea el comportamiento esperado de los programadores en los lenguajes funcionales, y menos para las personas con un historial de OOP. Por cierto, Haskell se comporta de la misma manera. 'test x = (x, 1) donde (x, 1) = (1, 2)' compila, pero falla al intentar llamar a 'test 2' con excepción' Patrón irrecuperable fallido para el patrón (x, 1) ' –

0

Como siempre, puede utilizar los trazos para escapar del nombre. No veo ningún problema para dar soporte a dichos nombres, ya sea que los use y funcionen para usted o que no funcionen para usted, y usted no los use.

+1

Backticks no funcionan para mí, ¿es esto lo que quieres decir? 'objeto Foo {val 1 = 2}; Foo. \ '1 \' ' –

+0

Sí, eso es lo que quise decir. –

4

por lo general hay dos factores en este tipo de decisión:

  1. Hay muchos errores en scalac que son mucho más alta prioridad, y los recursos son limitados corrección de errores. Este comportamiento es benigno y, por lo tanto, de baja prioridad.

  2. Hay un costo a largo plazo para cualquier aumento en la complejidad de la especificación del idioma, y ​​el comportamiento actual es coherente con la especificación. Una vez que las cosas comienzan a tener un revestimiento especial, puede haber un efecto de avalancha.

Es una combinación de estos dos.


actualización.Esto es lo que me parece extraño:

val pair = (1, 2) 
object Foo 
object Bar 

val (1, 2) = pair  // Pattern matching on constants 1 and 2 
val (Foo, Bar) = pair // Pattern matching on stable ids Foo and Bar 
val (foo, bar) = pair // Binds foo and bar because they are lowercase 
val 1 = 1    // Pattern matching on constant 1 
val Foo = 1   // *Not* pattern matching; binds Foo 

Si val 1 = 1 es la coincidencia de patrones, entonces ¿por qué se unen val Foo = 1Foo en lugar de coincidencia de patrón?

Actualización 2. Daniel Sobral señaló que esta es una excepción especial, y Martin Odersky recientemente wrote the same.

+0

'val Foo = 1' así como' val \ 'foo \' = 1' son las excepciones para permitir el enlace normal a estos identificadores. –

+0

@Daniel Para mí, parece más consistente no hacer una coincidencia de patrón si la expresión es un identificador único. Es decir, amplíe la "excepción" uniformemente. –

+0

@KiptonBarros: 1 no es un identificador, y queremos que 1 coincida con el patrón en 'x match {case 1 => ...}'. Parece que para tener uniformidad bajo las reglas actuales, val 1 = x debe interpretarse como coincidencia de patrones. Creo que en cambio uno podría prohibir las coincidencias de patrones que unen _no variables_ en las sentencias 'val', y esto también prohibiría 'val Seq() = expr', que podría reemplazarse por' assert (expr == Seq()) ', como 'val 1 = expr' es equivalente a' assert (expr == 1) '. [Estoy ignorando a propósito el hecho de que 'assert's se puede elidir, uno podría tener una afirmación no elidable si se desea]. – Blaisorblade

1

He aquí algunos ejemplos para mostrar cómo la LHS de una misión es algo más que un nombre:

val pair = (1, 2) 
val (a1, b1) = pair // LHS of the = is a pattern 
val (1, b2) = pair // okay, b2 is bound the the value 2 
val (0, b3) = pair // MatchError, as 0 != 1 
val a4 = 1 // okay, a4 is bound to the value 1 
val 1 = 1 // okay, but useless, no names are bound 
val a @ 1 = 1 // well, we can bind a name to a pattern with @ 
val 1 = 0 // MatchError 
Cuestiones relacionadas