It sounds really stupid, but i couldn't find the answer neither on StackOverflow or in Google as well. I need to make really simple and easy thing - pass to my TestNG test a Dataprovider that contains two numbers in each set, but i didn't manage to succeed with it . Here's my code:
#DataProvider(name = "numbersRandomRange")
def numbersRandomRange() = {
Array(Array(100, 150),
Array(100.10, 200.01),
Array(100.10f, 250.10f)
)
}
My test looks like this :
`
#Test(dataProvider = "numbersRandomRange")
def testNumbersRandomRange(min: Any, max: Any) {
def calculate(minValue: Any, maxValue: Any): Any = (minValue, maxValue) match {
case (min: Int, max: Int) => alpha.number(min, max)
case (min: Double, max: Double) => alpha.double(min, max)
case (min: Float, max: Float) => alpha.float(min, max)
}
val actualNumber = calculate(min, max)
logger.info("Checking custom number with type function. Should return with specific type and below specified value : ")
expectResult(actualNumber.getClass)(min.getClass)
assert(util.less(actualNumber, max))
assert(util.less(min, actualNumber))
}
`
When i try to run it, i get next Error Message :
Data Provider public java.lang.Object[] must return either Object[][] or Iterator [], not class [Ljava.lang.Object;
If you annotate the type then it works:
#DataProvider(name = "numbersRandomRange")
def numbersRandomRange():Array[Array[Any]] = { //Notice that the return type is set
Array(Array(100, 150),
Array(100.10, 200.01),
Array(100.10f, 250.10f)
)
}
The scala compiler is inferring the return type of numbersRandomRange to be Array[Array[_ >: Float with Double with Int <: AnyVal]] which is then probably interpreted by java to just be Object. By giving the compiler a hint, it makes this work.
Related
I've been learning Scala for a few days with TDD, so I have the following Unit Test:
test("CalcStats.calculateAverage should return average") {
assert(CalcStats.calculateAverage(Array(6, 9, 15, -2, 92, 11)) === 21.833333)
}
As far as I think, the following should make it pass:
def calculateAverage(values: Array[Int]): Float = {
values.sum / values.size
}
However, I am getting 21.0 instead of 21.833333, so the Unit Test will fail ❌
Expected :21.833333
Actual :21.0
As long as I am specifying that the result will be a Float, I thought that was enough, but it is definitely not. What should I do to avoid the truncation in the result?
Thanks in advance.
In
def calculateAverage(values: Array[Int]): Float = {
values.sum / values.size}
underlying result values.sum / values.size has type Int (21)
So, the compiler extend it to Float.
Try the following:
def calculateAverage(values: Array[Int]): Float = {
values.sum.toFloat / values.size }
This method should work - just a simple recursive method to add all the values from the list and, when empty, divide with the total size of the list.
def getAverage(list: List[Double]): Double = {
def loop(list: List[Double], acc: Double = 0): Double = {
list match {
case Nil => acc / list.size
case element :: tail => loop(tail, acc + element)
}
}
loop(list)
}
How can I get the type and the size of the type from T?
For example, when I'm trying to convert Integer or Long to ByteArray using generics in Scala, how can I get the type information from T?
def dataToByteArray[T](x: T) = {
if T is IntType
ByteBuffer.allocate(4).putInt(x).array()
else if T is LongType
ByteBuffer.allocate(8).putLong(x).array()
else
raise an error
}
I may use polymorphic functions, but I'm curious how scala can give the type info.
def dataToByteArray(x: Int) = {
ByteBuffer.allocate(4).putInt(x).array()
}
def dataToByteArray(x: Long) = {
ByteBuffer.allocate(8).putLong(x).array()
}
You can, but it is not that straightforward as in C/C++ -- in order to get estimate size of object of type T you have to traverse object's graph. There are some libraries for this, e.g. jamm.
Note, that usage of such libraries is extremely uncommon and very likely means that you're doing something wrong.
I had hit to an idea bellow!
def dataToByteArray[T](x: T) = {
x match {
case i: Int => ByteBuffer.allocate(4).putInt(x).array()
case l: Long => ByteBuffer.allocate(8).putLong(x).array()
case _ => throw new Exception("Runtime exception")
}
}
Note: this is a theoretical question, I am not trying to fix anything, nor am I trying to achieve any effect for a practical purpose
When creating a lambda in Scala using the (arguments)=>expression syntax, can the return type be explicitly provided?
Lambdas are no different than methods on that they both are specified as expressions, but as far as I understand it, the return type of methods is defined easily with the def name(arguments): return type = expression syntax.
Consider this (illustrative) example:
def sequence(start: Int, next: Int=>Int): ()=>Int = {
var x: Int = start
//How can I denote that this function should return an integer?
() => {
var result: Int = x
x = next(x)
result
}
}
You can always declare the type of an expression by appending : and the type. So, for instance:
((x: Int) => x.toString): (Int => String)
This is useful if you, for instance, have a big complicated expression and you don't want to rely upon type inference to get the types straight.
{
if (foo(y)) x => Some(bar(x))
else x => None
}: (Int => Option[Bar])
// Without type ascription, need (x: Int)
But it's probably even clearer if you assign the result to a temporary variable with a specified type:
val fn: Int => Option[Bar] = {
if (foo(y)) x => Some(bar(x))
else _ => None
}
Let say you have this function:
def mulF(a: Int, b: Int): Long = {
a.toLong * b
}
The same function can be written as lambda with defined input and output types:
val mulLambda: (Int, Int) => Long = (x: Int, y: Int) => { x.toLong * y }
x => x:SomeType
Did not know the answer myself as I never had the need for it, but my gut feeling was that this will work. And trying it in a worksheet confirmed it.
Edit: I provided this answer before there was an example above. It is true that this is not needed in the concrete example. But in rare cases where you'd need it, the syntax I showed will work.
I just start learning scala. I got an error "illegal start of simple expression" in eclipse while trying to implement a recursive function:
def foo(total: Int, nums: List[Int]):
if(total % nums.sorted.head != 0)
0
else
recur(total, nums.sorted.reverse, 0)
def recur(total: Int, nums: List[Int], index: Int): Int =
var sum = 0 // ***** This line complained "illegal start of simple expression"
// ... other codes unrelated to the question. A return value is included.
Can anyone tell me what I did wrong about defining a variable inside a (recursive) function? I did a search online but can't one explains this error.
A variable declaration (var) doesn't return a value, so you need to return a value somehow, here's how the code could look like:
object Main {
def foo(total: Int, coins: List[Int]): Int = {
if (total % coins.sorted.head != 0)
0
else
recur(total, coins.sorted.reverse, 0)
def recur(total: Int, coins: List[Int], index: Int): Int = {
var sum = 0
sum
}
}
}
The indentation seems to imply that recur is inside count, but since you did not place { and } surrounding it, count is just the if-else, and recur is just the var (which is illegal -- you have to return something).
I had a similar problem where I was doing something like
nums.map(num =>
val anotherNum = num + 1
anotherNum
)
and the way to fix it was to add curly braces:
nums.map { num =>
val anotherNum = num + 1
anotherNum
}
I thought these expressions were equivalent in Scala, but I guess I was wrong.
I had a similar problem. Found example 8.1 in the book that looked like:
object LongLines {
def processFile(filename: String, width: Int) **{**
val source = Source.fromFile(filename)
for (line <- source.getLines)
processLine(filename, width, line)
**}**
Note: the "def processFile(filename: String, width: Int) {" and ending "}"
I surrounded the 'method' body with {} and scala compiled it with no error messages.
I've defined multiple constructors, with some default argument values in all of them. Looks correct (I can't see any ambiguity), but Scala (2.8) compiler complains:
multiple overloaded alternatives of constructor define default arguments
Does it mean that I can't define default values for overloaded constructors at all?
Let me illustrate the situation (primitivized, of course, but illustrative):
class A(subject : Double, factor : Int = 1, doItRight : Boolean = true) {
def this (subject : Int, factor : Int = 1, doItRight : Boolean = true) = {
this(subject.toDouble , factor, doItRight)
}
def this (subject : String, factor : Int = 1, doItRight : Boolean = true) = {
this(subject.toDouble , factor, doItRight)
}
def this () = {
this(defaultSubject)
}
}
Taken straight from the compiler's source code:
// only one overloaded alternative is allowed to define default arguments
In general, I wouldn't advise that you mix overloading and defaults. Even if there's no conflict it can make your code harder to read.
UPDATE
Since you added code, it's clear now that you don't want/need to override the default values for each secondary constructor. In your particular case, I might even question the need for those extra constructors at all; Int=>Double is already available for you as an implicit conversion and String=>Double looks like you might be perverting the type system :)
Also... As an alternative to overloaded constructors, you can define just the primary constructor with defaults, then overload the apply method of the companion object and use that as a factory. This is of course completely optional, but it's rapidly becoming established as a pattern through the use of case classes.
The overloading fails because you (unnessesarily) define multiple constructors with default values. Do this instead:
class A(subject : Double, factor : Int = 1, doItRight : Boolean = true) {
def this (subject : Int) = {
this(subject.toDouble)
}
def this (subject : String) = {
this(subject.toDouble)
}
def this () = {
this(defaultSubject)
}
}
Yes, that's not convenient, you'll need to do without default arguments in your auxiliary constructors like:
class X(n: Int, verbose: Boolean = false) {
def this(n: String, verbose: Boolean) = this(
Integer.parseInt(n),
verbose
)
def this(n: String) = this(n, false)
}
Mind though that inline (within a function) with default arguments different from each other you can do that:
def main(args: Array[String]): Unit = {
class Y(n: Int, dummyImplicit: DummyImplicit = null, verbose: Boolean = false) {
def this(n: String, verbose: Boolean = false) = this(
Integer.parseInt(n),
verbose = verbose
)
}
}