Why this fails to compile:
scala> val a? = true
<console>:1: error: illegal start of simple pattern
val a? = true
^
and this works?
scala> val a_? = true
a_?: Boolean = true
According to the Scala language specification (looking at 2.8, doubt things have changed much since):
idrest ::= {letter | digit} [`_' op]
That is, an identifier can start with a letter or a digit followed by an underscore character, and further operator characters. That makes identifiers such as foo_!#! valid identifiers. Also, note that identifiers may also contain a string of operator characters alone. Consider the following REPL session:
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_16).
scala> val +aff = true
<console>:1: error: illegal start of simple pattern
val +aff = true
^
scala> val ??? = true
???: Boolean = true
scala> val foo_!#! = true
foo_!#!: Boolean = true
scala> val %^#%# = true
%^#%#: Boolean = true
scala> val ^&*!%# = 42
^&*!%#: Int = 42
Hope this answers your question.
Scala's grammar for identifiers is defined in such a way.
? is defined to be an operator character. And an identifier must obey the following rules:
it must be a lower-case letter which may be followed by an element of an 'idrest' syntactic category, which is defined as 'letters or digits, possibly followed by _ and an op char.'
See Scala Language Specification for more details.
Related
object solution extends App {
'n = 5
}
It gives the compile time Error: value update is not a member of object Symbol
println('n = 'n) which is understandable. Because literals are the fixed values in the source code. But what is the reason the above syntax is valid?
The reason the syntax is valid is … well … because it is:
implicit class UpdateableSymbol(val s: Symbol.type) extends AnyVal {
def update[A](s: String, v: A) = println(s"`Symbol.update` called with s = $s and v = $v")
}
'n = 5
// `Symbol.update` called with s = n and v = 5
As you can see, there is absolutely nothing wrong with the syntax, so why should it be invalid? The error message tells you what the problem is: you are calling Symbol.update but that doesn't exist. A missing method is not a syntactic error, it is a semantic error.
Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> reify('n)
res0: reflect.runtime.universe.Expr[Symbol] = Expr[Symbol](Symbol.apply("n"))
scala> val a = 'n
a: Symbol = 'n
scala> a = 5
<console>:15: error: reassignment to val
a = 5
^
scala> a.update(5)
<console>:16: error: value update is not a member of Symbol
a.update(5)
^
Desugar it, and you will find the answer.
In Scala, operators are methods.
For Symbol, see https://github.com/scala/scala/blob/2.13.x/src/library/scala/Symbol.scala
I have a class with getter/setter:
class Person {
private var _age = 0
//getter
def age = _age
//setter
def age_=(value: Int): Unit = _age = value
}
We know that we can invoke setter method like this:
val p = new Person()
p.age= (2)
p age= 11
p.age= 8-4
What made interesthing in this case is: the underscore (_) in def age_= can be removed when the method is invoked.
My question is what is the underscore used for in this case?
Someone told me it is used to separate non-alphanum character in identifier. So I tried this:
var x_= = 20
x_= = 10
x= = 5 // I got error here
Why I can't remove the underscore in this case?
Also, if I tried to use the underscore more than once:
val x_=_x = 1
I got compile error too.
Is there a rule about the underscore usage and what is the term for this underscore usage?
The compile error says it all, really:
scala> var x_= = 20
<console>:10: error: Names of vals or vars may not end in `_='
Only methods are allowed to have names ending in _=. This makes sense, because it would be really confusing to allow a val to be named x_=
However it is true that the underscore is used to separate alpha-numeric characters from special characters. It's just that in the case of a val or var, you can't end it with =
scala> var x_# = 20
x_#: Int = 20
scala> x_# = 10
x_$hash: Int = 10
I don't think another underscore is allowed after the first underscore that precedes special characters.
val x_y_^ = 1 // Ok
val x_^_^ = 1 // Not ok
Based on the Scala language spec :
First, an identifier can start with a letter which can be followed by an arbitrary sequence of letters and digits. This may be followed by underscore ‘’ characters and another string composed of either letters and digits or of operator characters.
See also Example 1.1.1 in the linked specification for examples of valid identifiers.
Is it possible to invert matches with Scala parser combinators? I am trying to match lines with a parser that do not start with a set of keywords. I could do this with an annoying zero width negative lookahead regular expression (e.g. "(?!h1|h2).*"), but I'd rather do it with a Scala parser. The best I've been able to come up with is this:
def keyword = "h1." | "h2."
def alwaysfails = "(?=a)b".r
def linenotstartingwithkeyword = keyword ~! alwaysfails | ".*".r
The idea is here that I use ~! to forbid backtracking to the all-matching regexp, and then continue with a regex "(?=a)b".r that matches nothing. (By the way, is there a predefined parser that always fails?) That way the line would not be matched if a keyword is found but would be matched if keyword does not match.
I am wondering if there is a better way to do this. Is there?
You can use not here:
import scala.util.parsing.combinator._
object MyParser extends RegexParsers {
val keyword = "h1." | "h2."
val lineNotStartingWithKeyword = not(keyword) ~> ".*".r
def apply(s: String) = parseAll(lineNotStartingWithKeyword, s)
}
Now:
scala> MyParser("h1. test")
res0: MyParser.ParseResult[String] =
[1.1] failure: Expected failure
h1. test
^
scala> MyParser("h1 test")
res1: MyParser.ParseResult[String] = [1.8] parsed: h1 test
Note that there is also a failure method on Parsers, so you could just as well have written your version with keyword ~! failure("keyword!"). But not's a lot nicer, anyway.
With Scala Reflection in 2.10, how can one determine if a type is a type alias?
The following does not work:
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> typeOf[String].typeSymbol.asType.isAliasType
res46: Boolean = false
This is a bug: https://issues.scala-lang.org/browse/SI-6474 caused by the fact that Type.typeSymbol automatically dereferences aliases.
scala> showRaw(typeOf[String])
res0: String = TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List())
scala> typeOf[String].typeSymbol
res1: reflect.runtime.universe.Symbol = class String
scala> typeOf[String].typeSymbol.asType.isAliasType
res2: Boolean = false
scala> val TypeRef(_, sym, _) = typeOf[String]
sym: reflect.runtime.universe.Symbol = type String
scala> sym.asType.isAliasType
res3: Boolean = true
A workaround, as partially provided by the REPL printout, is to perform manual pattern matching and extract the underlying symbol. An alternative is to cast to scala.reflect.internal.Types#Type and use typeSymbolDirect.
Note that, in addition of scala.reflect.internal.Types#Type, you need to avoid getClassByName(): following scala-dev issues 248, and PR 5482, Scala 2.12.1 will ensure that:
companionClass returns a class, not a type alias,
type aliases are not followed in getClassByName and friends.
This makes getClassByName fail / getClassIfDefined return NoSymbol when querying an alias.
The current behavior can confuse the classfile parser: when parsing a
class, a cross-check verifies that pool.getClassSymbol(nameIdx)
returns the symbol of the class currently being parsed.
If there's a
type alias that shadows the linked class, following the alias would
return an unrelated class.
Consider the following:
scala> val a:java.lang.Boolean = true
a: java.lang.Boolean = true
scala> val b = true
b: Boolean = true
scala> a == b
res4: Boolean = true
scala> b == a
<console>:8: warning: comparing values of types Boolean
and java.lang.Boolean using `==' will always yield false
b == a
^
res5: Boolean = true
The warning says that it will yield false but it yields true.
Scala 2.8.
A bit of source code control archaeology shows that handling of those warnings were improved after 2.8.1. Here is the annotated revisions to the unit tests for those warnings.
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/test/files/neg/checksensible.scala?annotate=blame&rev=25638
This is compared to rev 19169 in 2.8.1 final that is a lot more basic:
https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_1_final/test/files/neg/checksensible.scala
I think this gives a sense that more attention was provided to this after 2.8.1.
Looking at some bug reports, it seems the warning are really just that - hopefully helping identify errors. If you know what you're doing (such as comparing java Boolean and scala Boolean), then you can ignore.
Interestingly, this has regressed. In recent warning enhancements I must be excluding numerics and missing boolean. The error message in trunk for comparing java.lang.Boolean and Boolean is impressively confusing.