Scala's infix notation with object +, why not possible? - scala

I can name objects like this, but can't call m:
object + {
def m (s: String) = println(s)
}
Can't call +.m("hi"):
<console>:1: error: illegal start of simple expression
+.m("hi")
Also can't call + m "hi" (preferred for DSL-usage).
But with object ++ it works fine! Do they conflict with (not existent) unary_+ methods? Is it possible to avoid this?

Indeed it is not possible with unary operators. If you want to call it anyways, you could resort to using the name generated by the compiler for the JVM (which starts with a dollar):
scala> object + {
| def m( s: String ) = println(s)
| }
defined module $plus
scala> +.m("hello")
<console>:1: error: illegal start of simple expression
+.m("hello")
^
scala> $plus.m("hello")
hello

I believe the problem is that in order to handle unary operators without ambiguity, scala relies on a special case: only !, +, - and ~ are treated as unary operators. Thus in +.m("hi"), scala treat + as an unary operator and can't make sense of the whole expression.

Another code using package:
object Operator extends App {
// http://stackoverflow.com/questions/13367122/scalas-infix-notation-with-object-why-not-possible
pkg1.Sample.f
pkg2.Sample.f
}
package pkg1 {
object + {
def m (s: String) = println(s)
}
object Sample {
def f = {
// +.m("hi") => compile error: illegal start of simple expression
// + m "hi" => compile error: expected but string literal found.
$plus.m("hi pkg1")
$plus m "hi pkg1"
}
}
}
package pkg2 {
object + {
def m (s: String) = println(s)
}
object Sample {
def f = {
pkg2.+.m("hi pkg2")
pkg2.+ m "hi pkg2"
pkg2.$plus.m("hi pkg2")
pkg2.$plus m "hi pkg2"
}
}
}
java version "1.7.0_09"
Scala code runner version 2.9.2

Related

Trying to understand scala ^^ syntax

I'm beginner in scala and looking at this tutorial :
http://enear.github.io/2016/03/31/parser-combinators/
Event it is explained just below :
The ^^ operator acts as a map over the parse result. The regex
"[a-zA-Z_][a-zA-Z0-9_]*".r is implicitly converted to an instance of
Parser[String], on which we map a function (String => IDENTIFIER),
thus returning a instance of Parser[IDENTIFIER].
I dont understand this code snippet :
def identifier: Parser[IDENTIFIER] = {
"[a-zA-Z_][a-zA-Z0-9_]*".r ^^ { str => IDENTIFIER(str) }
}
Can someone explain the ^^ operator and how it is mapped to a block code ?
Thanks
It defines the operation that needs to be performed when the left-hand side expression is evaluated.
For instance, we have some code like this:
def symbol: Parser[Any] = "+" | "-" | "*"
def number: Parser[Int] = """(0|[1-9]\d*)""".r ^^ {string => string.toInt }
def expression = {
number ~ symbol ~ number ^^ { case firstOperand ~ operator ~ secondOperand =>
firstOperand + secondOperand
}
}
So, here in the number we will convert String to Int. This means that when we will use our parser like this:
parse(expression, "3 + 2")
It will return us 5, if we will not convert it and leave it as Strings we will get "32".

scala match on iteration, weird compiler error

This small piece of scala code when compiled
it gives a strange error.
import scala.collection.mutable.ListBuffer
object main {
def main(args: Array[String]) {
val rs = new ListBuffer[String]()
val ns = scala.collection.mutable.Map[String, String]()
"A very long string".split("\\ ") foreach { word =>
word match {
case x if x.length() > 7 => ns += x -> "="
case _ => rs += word
}
}
}
}
Gives the following error:
test.scala:11: error: type arguments [String,Iterable[java.io.Serializable] with PartialFunction[String with Int,String] with scala.collection.generic.Subtractable[String,Iterable[java.io.Serializable] with PartialFunction[String with Int,String] with scala.collection.generic.Subtractable[String,Equals]]{def seq: Iterable[java.io.Serializable] with PartialFunction[String with Int,String]}] do not conform to trait Subtractable's type parameter bounds [A,+Repr <: scala.collection.generic.Subtractable[A,Repr]]
"A very long string".split("\\ ") foreach { word =>
^
one error found
Any hints?
This happens due to the fact that your pattern match returns a lengthy compound type:
[String,Iterable[java.io.Serializable] with PartialFunction[String with Int,String] with scala.collection.generic.Subtractable[String,Iterable[java.io.Serializable] with PartialFunction[String with Int,String] with scala.collection.generic.Subtractable[String,Equals]]{def seq: Iterable[java.io.Serializable] with PartialFunction[String with Int,String]}]
Where one of the types in the linearization is Subtractable[String, Iterable[Serializable]] which your type doesn't conform to it's type constraint:
trait Subtractable[A, +Repr <: Subtractable[A, Repr]
To fix this, help the compiler out with type annotation on foreach:
"A very long string"
.split("\\")
.foreach[Unit] {
case x if x.length() > 7 => ns += x -> "="
case word => rs += word
}
As a side note, perhaps you can find the following implementation helpful:
val (largerThanSeven, smallerThanSeven) = "A very long string"
.split("\\")
.partition(_.length > 7)
val largerThanSevenMap = largerThanSeven.map(_ -> "=").toMap
The problem is here:
ns += x -> "="
I guess the intention is to put the key x and the value "=" into the mutable map.
This will compile if changed to
ns(x) = "="
The problem is that there are implicits involved into conversions with -> and the types are inferred weirdly into the monstrous string in the error message.

Is it possible to annotate lambda in scala?

For my dsl I need something in the spirit of:
#deprecated def foo(x: Int) = x
... only for lambdas\anonymous functions.
Is something like this possible?
Apparently this exists in the language according to the lang spec:
An annotation of an expression e appears after the expression e,
separated by a colon.
So this supposed to work:
object TestAnnotation {
val o = Some(1)
def f = o.map(_ + 1 : #deprecated("gone", "forever"))
val e = { 1 + 2 } : #deprecated("hmm", "y")
println(f)
println(e)
}
However, when I compile it with scalac -deprecation I get no warnings whatsoever. I opened an issue here and got a response that it's not supported.
One workaround you could use is to declare lambda separately:
object TestAnnotation {
val o = Some(1)
#deprecated("this", "works") val deprecatedLambda: Int => Int = _ + 1
o.map(deprecatedLambda)
}
scalac then gives:
Annotation.scala:6: warning: value deprecatedLambda in object TestAnnotation is deprecated: this
o.map(deprecatedLambda)
^
one warning found

scala parallel set recursive value needs type

I have a code from 'Scala in depth' that works in interactive editor:
(1 to 1000).par map { _ => Thread.currentThread.toString } toSet
This prints a set with threads that were used for this parallel operation. All works great and a result type is ParSet[String]
But then I try to use it in a code and I have this:
val pthr = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
//val x = pthr.toSet
println("thread = " + pthr)
This throws: " error: recursive value pthr needs type" in println line. Another observation is when I uncomment second line everything works fine and a result is ParSet().
What is going on here? What is a type of variable "pthr"?
The println method expects a string and you've provided a string with a + operator to pthr. In order to convert pthr to a string, the compiler needs to know which type it is. You haven't provided a type in your declaration of pthr but instead let it be inferred. For whatever reason, the inference isn't working so the compiler is requesting an explicit type declaration. You could simply do this:
val pthr : Set[String] = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
and that should take care of it.
However, I cannot reproduce your results with Scala 2.11.2. I get:
scala> val pthr = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
<console>:7: warning: postfix operator toSet should be enabled
by making the implicit value scala.language.postfixOps visible.
This can be achieved by adding the import clause 'import scala.language.postfixOps'
or by setting the compiler option -language:postfixOps.
See the Scala docs for value scala.language.postfixOps for a discussion
why the feature should be explicitly enabled.
val pthr = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
^
pthr: scala.collection.parallel.immutable.ParSet[String] = ParSet(Thread[ForkJoinPool-1-worker-29,5,main], Thread[ForkJoinPool-1-worker-19,5,main], Thread[ForkJoinPool-1-worker-13,5,main], Thread[ForkJoinPool-1-worker-3,5,main], Thread[ForkJoinPool-1-worker-27,5,main], Thread[ForkJoinPool-1-worker-5,5,main], Thread[ForkJoinPool-1-worker-1,5,main], Thread[ForkJoinPool-1-worker-23,5,main], Thread[ForkJoinPool-1-worker-15,5,main], Thread[ForkJoinPool-1-worker-11,5,main], Thread[ForkJoinPool-1-worker-21,5,main], Thread[ForkJoinPool-1-worker-9,5,main], Thread[ForkJoinPool-1-worker-7,5,main], Thread[ForkJoinPool-1-worker-17,5,main], Thread[ForkJoinPool-1-worker-31,5,main], Thread[ForkJoinPool-1-worker-25,5,main])
scala> println("thread = " + pthr)
thread = ParSet(Thread[ForkJoinPool-1-worker-29,5,main], Thread[ForkJoinPool-1-worker-19,5,main], Thread[ForkJoinPool-1-worker-13,5,main], Thread[ForkJoinPool-1-worker-3,5,main], Thread[ForkJoinPool-1-worker-27,5,main], Thread[ForkJoinPool-1-worker-5,5,main], Thread[ForkJoinPool-1-worker-1,5,main], Thread[ForkJoinPool-1-worker-23,5,main], Thread[ForkJoinPool-1-worker-15,5,main], Thread[ForkJoinPool-1-worker-11,5,main], Thread[ForkJoinPool-1-worker-21,5,main], Thread[ForkJoinPool-1-worker-9,5,main], Thread[ForkJoinPool-1-worker-7,5,main], Thread[ForkJoinPool-1-worker-17,5,main], Thread[ForkJoinPool-1-worker-31,5,main], Thread[ForkJoinPool-1-worker-25,5,main])
Other than the use of the toSet method as a postFix operator, there's nothing wrong with the code and it compiles and executes correctly. Perhaps you should check your version of the compiler?
Yes I know this works in interactive scala but doesn't during compilation by scalac.
Okay here is minimalistic example let's call this file "test.scala":
//test.scala
object test {
def main(args: Array[String]) = {
val pthr = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
println("thread = " + pthr)
}
}
Now let's execute in terminal:
-> scalac test.scala
test.scala:5: error: recursive value pthr needs type
println("thread = " + pthr)
^
one error found
-> scalac -version
Scala compiler version 2.11.2 -- Copyright 2002-2013, LAMP/EPFL
So again I have this issue only during compilation with scalac.
And when I add a type to pthr (val pthr: Set[String] = ...) then an error is:
test.scala:4: error: type mismatch;
found : Boolean
required: Set[String]
val pthr:Set[String] = (1 to 1000).par map { _ => Thread.currentThread.toString } toSet
^
one error found
No idea what is going on :/
BTW. this is the exact code copied from "Depth in scala" page 205.

Scala: 'implicit conversions are not applicable' in a simple for expression

I started out with Scala today, and I ran into an intriguing problem. I am running a for expression to iterate over the characters in a string, like such:
class Example {
def forString(s: String) = {
for (c <- s) {
// ...
}
}
}
and it is consistently failing with the message:
error: type mismatch;
found : Int
required: java.lang.Object
Note that implicit conversions are not applicable because they are ambiguous:
...
for (c <- s) {
^
one error found
I tried changing the loop to several things, including using the string's length and using hardcoded numbers (just for testing), but to no avail. Searching the web didn't yield anything either...
Edit: This code is the smallest I could reduce it to, while still yielding the error:
class Example {
def forString(s: String) = {
for (c <- s) {
println(String.format("%03i", c.toInt))
}
}
}
The error is the same as above, and happens at compile time. Running in the 'interpreter' yields the same.
Don't use the raw String.format method. Instead use the .format method on the implicitly converted RichString. It will box the primitives for you. i.e.
jem#Respect:~$ scala
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class Example {
| def forString(s: String) = {
| for (c <- s) {
| println("%03i".format(c.toInt))
| }
| }
| }
defined class Example
scala> new Example().forString("9")
java.util.UnknownFormatConversionException: Conversion = 'i'
Closer, but not quite. You might want to try "%03d" as your format string.
scala> "%03d".format("9".toInt)
res3: String = 009
Scala 2.81 produces the following, clearer error:
scala> class Example {
| def forString(s: String) = {
| for (c <- s) {
| println(String.format("%03i", c.toInt))
| }
| }
| }
<console>:8: error: type mismatch;
found : Int
required: java.lang.Object
Note: primitive types are not implicitly converted to AnyRef.
You can safely force boxing by casting x.asInstanceOf[AnyRef].
println(String.format("%03i", c.toInt))
^
Taking into account the other suggestion about String.format, here's the minimal fix for the above code:
scala> def forString(s: String) = {
| for (c: Char <- s) {
| println(String.format("%03d", c.toInt.asInstanceOf[AnyRef]))
| }}
forString: (s: String)Unit
scala> forString("ciao")
099
105
097
111
In this case, using the implicit format is even better, but in case you need again to call a Java varargs method, that's a solution which works always.
I tried your code (with an extra println) and it works in 2.8.1:
class Example {
| def forString(s:String) = {
| for (c <- s) {
| println(c)
| }
| }
| }
It can be used with:
new Example().forString("hello")
h
e
l
l
o