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
Related
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
assume two parsers: p & q.
now, given the following code:
val p1 = p | q
val p2 = "$" ~> p1 <~ "$"
something weird is happening. assume some string: val input = "..."
parseAll(p1, input)
succeeds with p's parsing result, but:
parseAll(p2, "$" + input +"$")
succeeds with q's parsing result.
the order is important. I only want to try q after p failed.
is there any way I can force the parser to evaluate p before q?
EDIT:
after checking the docs more carefully:
p | q succeeds if p succeeds or q succeeds.
Note that q is only tried if ps failure is non-fatal (i.e., back-tracking is allowed).
so my code should work.
so I tried reproducing with a simple example (my original code is too use case specific and most of it not relevant for here). but didn't quite succeed. instead, I managed to come up with a parser that fails when it should succeed. shown in the following REPL session:
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.util.parsing.combinator._
import scala.util.parsing.combinator._
scala> object MyParser extends RegexParsers {
| val xyz = "xyz".r ^^ { case s => Right(s) }
| val any = "\\S+".r ^^ { case s => Left(s) }
| val either: Parser[Either[String,String]] = xyz | any
| val wrapped = "$" ~> either <~ "$"
| def parseMeATest1(input: String) = parseAll(either, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| def parseMeATest2(input: String) = parseAll(wrapped, input) match {
| case Success(Right(s),_) => println(s"right: $s")
| case Success(Left(s),_) => println(s"left: $s")
| case NoSuccess(msg, _) => println(msg)
| }
| }
defined object MyParser
scala> MyParser.parseMeATest1("xyz")
right: xyz
scala> MyParser.parseMeATest1("zzz")
left: zzz
scala> MyParser.parseMeATest2("$xyz$")
right: xyz
scala> MyParser.parseMeATest2("$zzz$")
`$' expected but end of source found
So, am I missing something here, or this a bug with scala parsing combinators?
SOLVED:
problem was that p parser consumed the trailing $ character, causing overall failure, but since backtracking is used, q which does not consume the $ character completed successfully.
I'm trying to understand how function partial application works in Scala.
To do that, I've built this simple code:
object Test extends App {
myCustomConcat("General", "Public", "License") foreach print
GeneralPublicLicenceAcronym(myCustomConcat(_)) foreach print
def myCustomConcat(strings: String*): List[Char] = {
val result = for (s <- strings) yield {
s.charAt(0)
}
result.toList
}
def GeneralPublicLicenceAcronym (concatFunction: (String*) => List[Char] ) = {
myCustomConcat("General", "Public", "License")
}
}
myCostumConcat function takes in input an array of String and it returns a list containing the first letter of each string.
So, the code
myCustomConcat("General", "Public", "License") foreach print
will print on console: GPL
Suppose now that I want to write a function to generate the GPL acronym, using (as input parameter) my previous function extracting the first letter of each string:
def GeneralPublicLicenceAcronym (concatFunction: (String*) => List[Char] ): List[Char] = {
myCustomConcat("General", "Public", "License")
}
Running this new function with partial application:
GeneralPublicLicenceAcronym(myCustomConcat(_)) foreach print
I get this error:
Error:(8, 46) type mismatch; found : Seq[String] required: String GeneralPublicLicenceAcronym(myCustomConcat(_)) foreach print
Why? Can I use partial application in this case?
All you need to do is change myCustomConcat(_) to myCustomConcat _, or indeed just myCustomConcat
What you are doing isn't exactly partial application - it's just using a method as a function value.
In some cases (where a function value is expected) the compiler will work out what you mean, but in other contexts you often need to tell the compiler your intention, using the _ suffix.
"partial application" means that we are supplying some, but not all, of the arguments to a function, to create a new function, for example:
def add(x: Int, y: Int) = x + y //> add: (x: Int, y: Int)Int
val addOne: Int => Int = add(1, _) //> addOne : Int => Int = <function1>
addOne(2) //> res0: Int = 3
I suppose your case could be seen as partial application, but applying none of the arguments - you can use partial application syntax here, but you need to give a _* hint to the compiler because of the repeated parameters (String*), which ends up a bit ugly:
myCustomConcat(_:_*)
See also: Scala type ascription for varargs using _* cause error
I am reading Section 19.3 of the book "programming in scala 2nd",
there is a snippet code and some description around it in page 431:
NOTE: FC17 x86_64 Scala-2.9.2
class Cell[T](init: T) {
private[this] var current = init
def get = current
def set(x: T) { current = x }
}
I modifyed this sample in two different enviroments:
in first one, I wrote the following code in a file Cell.scala
class A
class B extends A
class C extends B
class Cell[+T](init: T) {
private[this] var current = init
def get = current
def set[U >: T](x: U) {
current = x.asInstanceOf[T]
println("current " + current)
}
}
object Cell {
def main(args: Array[String]) {
val a1 = new Cell[B](new B)
a1.set(new B)
a1.set(new String("Dillon"))
a1.get
}
}
and using the following command, and got nothing error:
[abelard <at> localhost lower-bound]$ scalac Cell.scala
[abelard <at> localhost lower-bound]$ scala -cp . Cell
current B <at> 67591ba4
current Dillon
Dillon
[abelard <at> localhost lower-bound]$
in the second, I directly wrote the code under the REPL:
scala> class Cell[+T](init: T) {
| private[this] var current = init
| def get = current
| def set[U >: T](x: U) {current = x.asInstanceOf[T]
| }}
defined class Cell
scala> val a1 = new Cell[B](new B)
a1: Cell[B] = Cell <at> 6717f3cb
scala> a1.set(new B)
scala> a1.set(new String("Dillon"))
scala> a1.get
java.lang.ClassCastException:
java.lang.String cannot be cast to B
at .<init>(<console>:25)
at .<clinit>(<console>)
accordding to my uderstanding to covariant and lower-bound,
I think the second result is right, but I do not know why
the first one did not throw any error?
I know I must missing something, I want to get a compiling
error as the second, what should I do?
You're not going to get a compile error, because there's no problem at compile time. A ClassCastException is a runtime exception.
You should notice that the exception occurs after you evaluate a1.get, rather that when you perform the cast in a1.set. More precisely, it occurs when you try to assign that return value to a variable.
In your first scenario a1.get is not assigned to a value. In your second, you're assigning it to a value such as res0 etc.
You can show that this is the problem by trying the following in the REPL:
scala> a1.get
java.lang.ClassCastException: java.lang.String cannot be cast to B
scala> println(a1.get)
Dillon
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