I have been trying to use the Int type like this: 10 twotimes.
It is similar to Akka's duration package which allows to write for example 10 minutes and 5 seconds.
I did the following:
object ImplicitConversion2 {
class Test(val a:Int) {
def threetimes = a * 3
}
implicit def IntToTest(e:Int) = new Test(e)
5.threetimes //> res0: Int = 15
10.threetimes //> res1: Int = 30
11.threetimes //> res2: Int = 33
}
In this case, I can use threetimes like 10.threetimes, that is with a dot between 10 and threetimes. I want to eliminate the dot between the Int and threetimes.
But if I write 5 threetimes, an error occurs.
How can I do that?
Which version of Scala are you referring to? With version 2.10.1 I get a feature warning, namely that I should add the following
import scala.language.implicitConversions
to activate implicit conversions. After doing so, as you said, 10.threetimes works fine, but for 10 threetimes I get another feature warning which tells me to add:
import scala.language.postfixOps
to enable postfix operators. After doing so, everything works fine.
EDIT: Here is an excerpt from the original SIP (to be found here) which gives the reason why postfix operators are now discouraged by default (i.e., you will get a warning if you use them; in later versions this might turn into an error instead of a warning):
postfixOps. Only where enabled, postfix operator notation (expr op) will be allowed. Why keep the feature? Several DSLs written in Scala need the notation. Why control it? Postfix operators interact poorly with semicolon inference. Most programmers avoid them for this reason.
As Luigi Plinge correctly states in his comment, the compiler tries to use the line after a call to a postfix operator as argument. If you look at the error message it becomes clear:
<console>:10: error: Int does not take parameters
3 threetimes
This error means, that it tries to use something as an argument, where it doesn't belong. The fact, that using dot-notation fixes this error should make it obvious, what goes wrong. The only way to safely use postfix operators is to pass them as arguments, where either the ) or the , terminates the expression.
def foo(x: Int, y: Int) = x + y
foo(4 threetimes, 8 threetimes)
Related
I'm using Scala 2.12.1. In the Interpreter I make an Int val:
scala> val someInt = 3
someInt: Int = 3
Then I tried to use the eta expansion and get the following error:
scala> someInt.== _
<console>:13: error: ambiguous reference to overloaded definition,
both method == in class Int of type (x: Char)Boolean
and method == in class Int of type (x: Byte)Boolean
match expected type ?
someInt.== _
^
I see in the scaladoc that the Int class has more than 2 overloaded methods.
Question: is there a particular reason that the error message shows only 2 overloaded methods as opposed to listing all of them?
By the way, to specify which method you want to use the syntax is this:
scala> someInt.== _ : (Double => Boolean)
res9: Double => Boolean = $$Lambda$1103/1350894905#65e21ce3
The choice of the two methods that are listed seems to be more or less arbitrary. For example, this snippet:
class A
class B
class C
class Foo {
def foo(thisWontBeListed: C): Unit = {}
def foo(thisWillBeListedSecond: B): Unit = {}
def foo(thisWillBeListedFirst: A): Unit = {}
}
val x: Foo = new Foo
x.foo _
fails to compile with the error message:
error: ambiguous reference to overloaded definition,
both method foo in class Foo of type (thisWillBeListedFirst: this.A)Unit
and method foo in class Foo of type (thisWillBeListedSecond: this.B)Unit
match expected type ?
x.foo _
That is, it simply picks the two last methods that have been added to the body of the class, and lists them in the error message. Maybe those methods are stored in a List in reverse order, and the two first items are picked to compose the error message.
Why does it do it? It does it, because it has been programmed to do so, I'd take it as a given fact.
What was the main reason why it was programmed to do exactly this and not something else? That would be a primarily opinion-based question, and probably nobody except the authors of the Scala compiler themselves could give a definitive answer to that. I can think of at least three good reasons why only two conflicting methods are listed:
It's faster: why search for all conflicts, if it is already clear that a particular line of code does not compile? There is simply no reason to waste any time enumerating all possible ways how a particular line of code could be wrong.
The full list of conflicting methods is usually not needed anyway: the error messages are already quite long, and can at times be somewhat cryptic. Why aggravate it by printing an entire wall of error messages for a single line?
Implementation is easier: whenever you write a language interpreter of some sort, you quickly notice that returning all errors is somewhat more difficult than returning just the first error. Maybe in this particular case, it was decided not to bother collecting all possible conflicts.
PS: The order of the methods in the source code of Int seems to be different, but I don't know exactly what this "source" code has to do with the actual Int implementation: it seems to be a generated file without any implementations, it's there just so that #scaladoc has something to process, the real implementation is elsewhere.
I have written the following Scala code:
class MyTestApi {
private def toCPArray(inputStr: String): Array[Int] = {
val len = inputStr.length
//invoke ofDim of Scala.Array
val cpArray = Array.ofDim[Int](inputStr.codePointCount(0, len))
var i = 0
var j = 0
while (i < len) {
cpArray(j += 1) = inputStr.codePointAt(i)
i = inputStr.offsetByCodePoints(i, 1)
}
cpArray
}
}
This is what I want to accomplish:
I would create an instance of class MyTestApi and then invoke the method toCPArray and pass to it a parameter of type String. I would then like this method to return me an `Array[Int].
However as it stands now, the Scala IDE is complaining about this line:
**cpArray(j += 1) = inputStr.codePointAt(i)**
type mismatch; Found: Unit required: Int
Two things I would like to accomplish are:
How would I fix this method? (or is it a function)
My hope is, after I understand what it takes to fix this method (or function) I will be able to return the appropriate type. Also, I should be in better position to understand the difference between a method and a function.
So far my research on stackoverflow and Martin Odersky's book seems to suggests to me that what I wrote is a method because it is invokded on an instance of the underlying class. Is my understanding right on that?
After it is fixed, how can i rewrite it in a more Scalaesque way, by getting rid of the var. The code looks more C or java like right now and is a little long in my opinion, after all that I have studied about Scala so far.
Thanks for any help in refactoring the above code to accomplish my learning objectives.
You are calling cpArray.update with an assignment statement which evaluates to Unit when it expects an Integer. You need to call it with an Integer:
j += 1
cpArray(j) = inputStr.codePointAt(i)
Many questions in one. I try to answer them all.
First of all as Jörg pointed out, moving the assignment makes the code work. Contrary to Java and C, Scala's assignment doesn't return the assigned value but Unit.
Now for making it idiomatic. Scala's String can be seem as IndexedSeq[Char], meaning you can generally treat them as IndexedSeqs. So you doing do something like:
inputStr.map{ x => x.toInt }.toArray
This will return an Array[Int]. Notice it will only work for 16-bits char representations. Hopefully it will help in giving an idea of idiomatic Scala, even not being a perfect solution.
For the difference between methods and functions, it's simple: methods are generally defs in a class. Functions one the other hands are Objects in the JVM sense. For example, the above map could be defined like:
def map(f: Function1[Char, Int]):IndexedSeq[Int]
// or
def map(f: Char => Int):IndexedSeq[Int]
Both are the same, => desugars to one of the scala.FunctionN (N from 0 to 22 inclusive).
And x => x.toInt is desugared in a similar way into a instance of scala.Function1. See it's Scaladoc.
So, functions are objects of type scala.FunctionN.
Note: to keep things simple I omitted a few details like type parameters, vals (which often compiles to JVM methods) and probably a few more details.
If I can do this:
var num: Int = 1
num += 1
print(num)
Why can’t I do this? What would be the correct way? Fails on line 4
var num: Int = 1
def someFunction(num:Int){
num += 1
}
someFunction(num)
print(num)
Thanks for any insight. I've done some searching but nothing too helpful. I am mostly looking for the theory behind why this fails. I have accomplished what I need to with for statements but I am still wondering why this fails. Thanks!
It's a similar behavior to what you would see in Java. In Java and Scala you pass by value. A reference to your object/argument is copied and passed into the function. Thus, even if you would be able to change the value of that reference (num:Int) you would be working with a copy of that value - essentially a reassignment. Reassignment to arguments is allowed in Java by default but not in Scala. In other words there is nothing like C/C++ has where you can reference external variable and modify its value. That being said you can still achieve similar effect if the value you are trying to modify is an object field:
// I'm changing it directly but you could have a setter instead:
scala> class A(var m: Int)
defined class A
scala> val a = new A(0)
a: A = A#469c3554
scala> a.m
res0: Int = 0
scala> def someFunction(a: A, newVal: Int): Unit = { a.m = newVal }
someFunction: (a: A, newVal: Int)Unit
scala> someFunction(a, 3)
scala> a.m
res2: Int = 3
Using mutable state like this is NOT recommended. This example is just for illustration purposes. In this case you pass a copy of object reference a from which you can access the field directly and modify it.
If you want to understand this better read up on passing by value and passing by reference. Contrast C/C++ pointer and by reference args with Java and Scala. One difference between Scala and Java here is that in Java everything is a var by default, so if you write your arg as final num in Java it will also fail compilation and will work similarly to Scala in this case.
Because the JVM uses call-by-value semantics, and because Int is a primitive type (not an object reference).
What this means is that num inside the method is not the same as num on the outside, the only thing passed to the method is 1
It's a good thing too... It's bad enough when you have a mutable object and some innocent-looking method goes and changes things around behind your back. I don't wish to imagine the new category of bugs that would emerge if the same risk also existed for simple numbers!
#flavian's link answers the "why not" part, but here's how you do what you're trying to do. Make someFunction a function instead of a procedure.
var num = 1
def someFunction(num: Int) = num + 1
num = someFunction(num)
Note though that this isn't idiomatic scala. Avoid using vars whenever you can for best style.
Or alternatively for even worse style (seriously, this works, but don't ever do it):
var num = 1
def someFunction() = num += 1
someFunction()
print(num)
Main.scala:
package controler
object Main {
def main(args: Array[String]) {
import Utilites._
isJavaUpToDate
}
}
Utilites.scala:
package controler
object Utilities {
def isJavaUpToDate = {
val javaVersion = augmentString(System.getProperty("java.version").substring(2, 3))
javaVersion >= 6
}
}
Why isn't this working?
I have been trought a bunch of differenet tutorial sites where this works no problem.
I always says that val Utilites cannot be found.
P.S. Why does it keep sugesting me to change .toInt with augmentString() when it just breaks the code?
Now this gives me trouble, something about implicit ordering and method orderTOOrdered.
In your main method you've typed Utilites where you meant to type Utilities.
Correct: Utilities
Wrong: Utilites
Note the missing i :) And because your brain is a powerful spelling correction tool, it pretended like the spelling was correct. The Scala compiler isn't as cool, though ;)
Also, for me, the following does not work:
scala> augmentString(System.getProperty("java.version").substring(2, 3)) >= 5
<console>:15: error: No implicit Ordering defined for AnyVal.
augmentString(System.getProperty("java.version").substring(2, 3)) >= 5
Instead I replaced it with
System.getProperty("java.version").substring(2, 3)).toInt >= 5
The implicit ordering issue you experienced with the former code is because Scala does not know how to apply the >= method/operator to the type scala.collection.immutable.StringOps, which augmentString() returns.
Note that by calling augmentString you're explicitly transforming your string to a StringOps.
StringOps does define a >= method, but it's meant to compare strings (its signature is def >=(that: String): Boolean )
If you want to compare Ints you should use the toInt method defined in StringOps.
def isJavaUpToDate = {
val javaVersion = augmentString(System.getProperty("java.version").substring(2, 3)).toInt
javaVersion >= 6
}
Also, unless you need to disambiguate the toInt against another implicit that you defined (or is defined somewhere else in a library you're using) there should be no need to call augmentString explicitly. The following should just work (unless the compiler tells you it does not) and it should implicitly have the same effect as the code above of transforming your String to a StringOps.
def isJavaUpToDate = {
val javaVersion = System.getProperty("java.version").substring(2, 3)
javaVersion.toInt >= 6
}
EDIT: as per #som-snytt's comment
The error you're getting (No implicit Ordering defined for AnyVal) is due to the compiler reasoning more or less like this:
javaVersion >= 6 means javaVersion.>=(6), i.e. I must look for a method called >= on javaVersion that takes an integer
javaVersion is a StringOps... there is a >= method in StringOps (courtesy of the StringLike trait it's extending, that in turn extends Ordered[String]) but it takes a String argument, not an Int
let's see if I have an implicit in scope that supplies a suitable Ordering for StringOps. Now, since you're trying to compare a String with a Int you're looking at an Ordering that can compare two values with the nearest common ancestor that can contain both String and Int, i.e. AnyVal [EDIT: although String is an AnyRef so I don't really get this part...].
No luck there... give up with an error that says that no implicit Ordering was found comparing AnyVals
I don't understand why the following code doesn't compile:
class Abc
{
def b (x : String) = x + "abc"
def a (y : String) =
{
val ls : List[String] = y.lines toList
b (ls.head)
}
}
Main.scala:8: error: type mismatch;
found : java.lang.String
required: Int
b (ls.head)
When I change "y.lines toList" to
y.lines.toList
or even to
y.lines toList;
it does compile.
Perhaps the compiler understands it like
(y.lines).toList(b (ls.head))
or something like that, but I still don't understand the rules.
It's not obvious, and it's a combination of Scala's shortcut syntax and list indexing. If you want a hint, try redefining b to:
def b(x : String) = 0
You'll get some other compiler garbage back, but the error will change. In short, the Scala compiler will let you omit parens and dots for zero- or one-parameter methods, and we know b looks like it's somehow getting chained.. The rub is that Scala also uses parens for list indexing, so toList, which returns an iterator, may take one parameter as the list index. I'm not sure of this part exactly, but it looks like once you start omitting dots, the lexer will become greedy, and when it comes across a method that may take one parameter, will attempt to pass the next statement to it. In this case, that's a string, so it throws a syntax error.
You got it spot on with this:
(y.lines).toList(b (ls.head))
With the only possible correction being:
(y.lines).toList(b).apply(ls.head)
I'm not sure that Scala would decide in this particular case.
The rule, roughly speaking, is object (method parameters)* [method]. The compiler will continue as long as it finds tokens for a valid expression. A ; finishes the expression, and so would a ) or }. If the next line is blank, the expression also ends. If the next line begins with a reserved keyword (val, def, if, etc), the expression would end too.