Scala right associative methods - scala

I am learning Scala, and playing with right associate unapply object. I know that if the name ends with ':' then it becomes right associative. However, there seems to be some strange restrictions on the naming
e.g.
These are invalid
object cons: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
object :_cons_: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
These are valid
object cons_: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
object >>: { def unapply(value: String): Option[(Char, List[Char])] = ??? }
So there seems to be some weirdness about mixing alpha-numeric characters and symbols in identifiers.
So basically, I want to have a descriptive name i.e. 'cons' and still have right associativity. Also, I would like my operator to be symetric for aesthetic reasons :-), so I dont really like cons_:
Is there a way to make something associate to the right without using a colon? Or any other suggestions to achieve this?
:_cons_: seems to be the closest, but, for some reason the identifier can't start with ':' and have alphanumerics

From the spec (section 1.1):
There are three ways to form an identifier. 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. Second, an identifier can start with an operator
character followed by an arbitrary sequence of operator characters.
The preceding two forms are called plain identifiers. Finally, an
identifier may also be formed by an arbitrary string between
back-quotes (host systems may impose some restrictions on which
strings are legal for identifiers). The identifier then is composed of
all characters excluding the backquotes themselves.
So it looks like you're out of luck—if your identifier starts with a : it can't contain non-operator characters. Note, though, that you can write the following (which isn't intended to do anything meaningful—just to demonstrate the syntax):
scala> class X { def `:cons:`(i: Int) = i }
defined class X
scala> val x = new X
x: X = X#6a665da6
scala> 1 `:cons:` x
res1: Int = 1
The method name still ends with a colon, so you get the right associativity you're looking for.

Related

Scala: Swapping the case of each character in a string

Using Scala I want to take a sub string of an initial string and swap each characters case so that capital letters become lower case lower case become upper.
var swapCase = buffer.substring(lwr, upr).to?OTHER?Case
I have used the .toUpperCase and .toLowerCase commands in the past and was wondering if there is a similar command for just swapping case without having to iterate through each character within a loop and evaluating which operation needs to be performed on each character i.e:
if(char(x).isUpperCase){char(x).toLowerCase}
else if(char(x).isLowerCase){char(x).toUpperCase}
In short, is there a really quick way to do this with a "." command instead of writing multiple lines.
This is about as good as you are going to get:
def swapCase(s: String): String =
s.map(ch => if (ch.isLower) ch.toUpper else ch.toLower)
An alternative to the Tim's oneliner could be:
def swapCharCase(ch: Char) = if (ch.isLower) ch.toUpper else ch.toLower
def swapCase(s: String): String = s.map(swapCharCase)
I find it a tiny bit more readable - and perhaps swapCharCase may become handy anyway.
To use it as .swapCase as requested, use an implicit class instead to provide the extension method:
implicit class CaseStringOps(s: String) {
def swapCase: String = s.map(swapCharCase)
}

error: left- and right-associative operators with same precedence may not be mixed

I'm trying to make a URI DSL in Scala, but infix methods are really giving me trouble.
Even after committing the lengthy and very unintuitive precedence rules to memory, they are still giving me trouble.
class Foo {
def `://`(a: Unit) = this
def `:`(b: Unit) = this
}
object Foo {
def main(args: Array[String]): Unit = {
new Foo `://` {} `:` {}
}
}
yields
left- and right-associative operators with same precedence may not be mixed
new Foo `://` {} `:` {}
^
What does this mean? I thought all operators were left-associative.
Is there any way for me to write a DSL that looks like this?
"https" `://` "example.com" `:` 80
There are two troubles in operators name you have chosen:
Name :// contains double slash, so without backquotes compiler can misinterpret it as comment
Name : as all other operators ending with : creates right associative operator, this is handy for operators like :: or #:: for building sequences starting from head. Operators with different associativity are not allowed without parenthesis since it's not clear where you should start building you expression.
So my suggestion is get rid of double slash and colon-ending, create maybe a little bit confusing, but correct DSL syntax:
object URILanguage extends App {
case class URL(protocol: String, hostname: String, port: Option[Int] = None, path: Seq[String] = Nil) {
def %(port: Int) = copy(port = Some(port))
def /(component: String) = copy(path = path :+ component)
}
implicit class WithHostname(protocol: String) {
def ~(hostname: String) = URL(protocol, hostname)
}
println("http" ~ "example.com" % 8080 / "mysite" / "index.html")
}
From The Scala Language Specification, section 6.12.3:
The associativity of an operator is determined by the operator’s last
character. Operators ending in a colon ‘:’ are right-associative. All
other operators are left-associative
The compiler doesn't know whether to interpret your code as this:
80.`:`("https".`://`("example.com"))
or this:
"https".`://`(80.`:`("example.com"))
I don't think there's a way to prevent ':' from being treated as a right-associative operator. You could help the compiler out by using parentheses; otherwise, you have to change your operator names.

Underscore usage in Scala's identifier

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.

Expressing square in Scala

For some reason (that escapes me), Scala math library does not have a pow-function for integers, but only for Doubles.
I need a square function for integers and was figuring what might be the usual way to do this in Scala.
object TestX extends App {
def pow2(v: Int)= v*v
//class MyRichInt( val v: Int ) {
// def ² : Int = v*v // says: "illegal character" for UTF-8 power-of-two
//}
println( pow2(42) )
//println( 42² )
println( math.pow(42,2).toInt )
}
I was surprised to see that the '²' character is not liked by Scala. Maybe it's taken to be a number? Usually all kinds of weird Unicode values are valid and using 42² in code would, indeed, be fancy.
Never mind. Should I shut up and just start using my own pow2 function?
Yes, use your own pow2. If you need higher powers, you probably won't have room in an Int anyway. Consider using BigInt.pow:
scala> BigInt(40).pow(40)
res0: scala.math.BigInt = 12089258196146291747061760000000000000000000000000000000000000000
Of course, if you need not N2 but 2N, just use shifts. (1 << k = 2k) These work with BigInt also.
Use backticks for Unicode characters, and implicit classes (Scala 2.10) to add operation on arbitrary types:
implicit class PowerInt(i: Int) {
def `²`: Int = i * i
}
Usage:
3 `²`
Result:
9

Pattern matching a String as Seq[Char]

In Scala it is possible formulate patterns based on the invididual characters of a string by treating it as a Seq[Char].
An example of this feature is mentioned in A Tour of Scala
This is the example code used there:
object RegExpTest1 extends Application {
def containsScala(x: String): Boolean = {
val z: Seq[Char] = x
z match {
case Seq('s','c','a','l','a', rest # _*) =>
println("rest is "+rest)
true
case Seq(_*) =>
false
}
}
}
The problem I have with this is the third line of the snippet:
val z: Seq[Char] = x
Why is this sort of cast necessary? Shouldn't a String behave like a Seq[Char] under all circumstances (which would include pattern matching)? However, without this conversion, the code snippet will not work.
There is some real abuse of terminology going on in the question and the comments. There is no cast in this code, and especially "So basically, this is a major concession to Java interoperability, sacrificing some type soundness" has no basis in reality.
A scala cast looks like this: x.asInstanceOf[Y].
What you see above is an assignment: val z: Seq[Char] = x
This assignment is legal because there is an implicit conversion from String to Seq[Char]. I emphasize again, this is not a cast. A cast is an arbitrary assertion which can fail at runtime. There is no way for the implicit conversion to fail.
The problem with depending on implicit conversions between types, and the answer to the original question, is that implicit conversions only take place if the original value doesn't type check. Since it's perfectly legal to match on a String, no conversion takes place, the match just fails.
Not 100% sure if this is correct, but my intuition says that without this explicit cast you would pattern match against java.lang.String, which is not what you want.
The explicit cast forces the Scala compiler to use Predef.stringWrapper implicit conversion; thus, as RichString extends Seq[Char], you are able to do a pattern match as if the string were a sequence of characters.
I'm going to echo everything that andri said. For interoperability, Scala strings are java.lang.Strings. In Predef, there's an implicit conversion from String to RichString, which implements Seq[Char].
A perhaps nicer way of coding the pattern match, without needing an intermediate val z to hold the Seq[Char]:
def containsScala(x: String): Boolean = {
(x: Seq[Char]) match {
...
}
}