I am reading the source code of the class kafka.core.log.LogSegment. Where the syntax of scala gives me huge confusion. I know I could make it clear if I can learn scala in a systematic way But I just don't have that much time since my project awaits.
Definition of the methods:
#volatile private var _maxTimestampSoFar: Option[Long] = None//**#pos 0 constructor??**
def maxTimestampSoFar_=(timestamp: Long): Unit = _maxTimestampSoFar = Some(timestamp)//**definition 1**
def maxTimestampSoFar: Long = {//**definition2**
if (_maxTimestampSoFar.isEmpty)
_maxTimestampSoFar = Some(timeIndex.lastEntry.timestamp)
_maxTimestampSoFar.get
}
Where they are called:
if (largestTimestamp > maxTimestampSoFar) {//**#pos 3.getter**
maxTimestampSoFar = largestTimestamp//**#pos4 set the value?**
offsetOfMaxTimestampSoFar = shallowOffsetOfMaxTimestamp
}
What confuses me can be concluded into the following:
What is usage of this kind of method with an extra "_" after the identifier of the method like this one here: the maxTimestampSoFar_.
When I checked the usage of definition 1 and definition 2, there occurrence overlaps, from which can I conclude they are regarded as the same method like overloaded twins?But since they have different parameters, why we need a difference in the identifier?
As for the place the method is called, is my understanding correct? Is pos 4 the place where definition 1 of the method is called? Then the argument of the parameter is passed just by using the "=" ?
If the second assumption is correct, then the at above pos 0, is it the call of Option's constructor? This is like calling the default constructor?
Hope anyone can help me. Appreciate that.
The method name contains also the equals sign, so is maxTimestampSoFar_=. That is how setters are defined in Scala (see Scala getters/setters - best practice?)
Yes, what looks like an assignment in pos 4 will invoke the method defined in 1
Option[Long] can either contain None or Some(<long value>), pos 0 in the code initializes the variable with value None
Related
I'm trying to create a class with an attribute named _1d_matrix, which is a 1D matrix. I would want to fill it with 0.
Thus, I tried to call the method empty of the Seq object (of course not the trait), as mentionned in the documentation : http://www.scala-lang.org/api/2.12.3/scala/collection/Seq$.html#empty[A]:CC[A]
For the moment my code is :
class Calc(val width : Int) {
private val _1d_matrix : Seq.empty[Int]()
}
But there are three errors :
empty is undefined
() can't be written (2 errors : "; or newline is expected" + "definition or declaration is expected")
I think it's because it's not allowed to directly make use of Seq instead of List (e.g.). But : why ? After all, Seq is an object (and a trait but not in my code).
Right way to initialize field looks like this:
private val _1d_matrix = Seq.empty[Int]
or
private val _1d_matrix: Seq[Int] = Seq()
There are two ways to define a 0-arity (no arguments) method in scala - with a pair of parenthesis after the name def exit(), and without one: def empty.
When it is defined in the former way, you can call it with or without parenthesis: exit() or exit - both work. But when parenthesis are not included into the method definition, you can not have them at the call site either: Seq.empty[Int] works, but Seq.empty[Int]() does not.
The convention is to use parenthesis for functions that have side effects, and not use them for purely functional calls.
The other problem with your code is that you have a : where it needs to be an assignment.
So, something like this should work:
val _1d_matrix = Seq.empty[Int]
Your thinking is correct but you have a couple syntax errors.
private val _1d_matrix : Seq.empty[Int]()
: here is used to define a type annotation, so it's trying to find the type Seq.empty rather than the method. That fails because there is no such type.
Use = instead to assign a value. Adding the type here is optional since Scala is able to infer the correct type.
The other is that the empty method is defined without parens, so you must use Seq.empty[Int] instead of Seq.empty[Int]()
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.
I am confused when I first come across the following piece of code.
In the class Element, there are three function definitions.
Why height and width can use contents directly as a variable of Array[String]?
Is it because every function in Scala is an object or some other rule?
I come from C++ world, so the definition really puzzles me.
abstract class Element {
def contents: Array[String]
def height: Int = contents.length
def width: Int = if (height == 0) 0 else contents(0).length
}
This is just syntax. The expression contents.length, for example, is compiled into a call of the contents method followed by a call of the length method on the result.
In general, parentheses can be omitted on zero-argument method calls. In fact, parentheses must be omitted when calling methods, such as your contents method, that have no parameter list in their definitions.
Note that this feature is part of Scala's commitment to the uniform access principle. The contents method could be replaced with a contents property without breaking callers.
Nothing very special is going on. Compared to C++, you're hitting the follownig differences:
invocation of methods without arguments in Scala doesn't need parentheses - length in this case is the same as length()
method definitions don't need to be wrapped in {} if they contain only one expression
functions return the value of the last expression in their body
A more C/Java like way to write this would be
def height() : Int = { return contents.length(); }
which would do the same, but be much more verbose - a nice demonstration of why Scala is an awesome language for reading code.
It's easy enough to create:
object zero extends BigDecimal(java.math.BigDecimal.ZERO)
I'm just wondering whether this was an oversight, or if there was a conscious decision to not add this and, if so, are there reasons why I should avoid the code above. Perhaps having to do with the MathContext?
If I had to guess, it's because the expected way to get that value would be like this:
val zero: BigDecimal = 0
I'd think it's because usually you don't need it. Whereas in Java you need to type something like
BigDecimal b = new BigDecimal(1.23).add(BigDecimal.ZERO);
in Scala, there are number conversions that mean you can write
val b = BigDecimal(1.23) + 0
You can also write it simply as BigDecimal(0). If you're instantiating that a lot you might want to cache it as a named value (as for any other number), but you won't normally need to, and I think it helps simplify the API if you remove special cases that you have to remember.
Resurrection of an old thread for the sake of completeness. Scala actually has something similar to java BigDecimal.ZERO, you can access it with BigDecimalIsFractional.zero.
As previous answers already pointed out most of the time the literal 0 will be fine. Having said that, Context Bounds can be useful with generic code:
def zero[T: Numeric](): Unit = {
val evidence = implicitly[Numeric[T]]
val zero = evidence.zero
println(s"${zero} is a ${zero.getClass.getSimpleName} defined at ${evidence.getClass.getName}")
}
zero[BigDecimal]() // 0 is a BigDecimal defined in scala.math.Numeric$BigDecimalIsFractional$
zero[Double]() // 0.0 is a Double defined in scala.math.Numeric$DoubleIsFractional$
zero[Int]() // 0 is a Integer defined at scala.math.Numeric$IntIsIntegral$
I'm following a groovy tutorial and there is a code like this:
def fruit = ["apple", "orange" , "pear"] //list
def likeIt = { String fruit -> println "I like " + fruit + "s" } //closure
fruit.each(likeIt)
Eclipse reports an error at closure definition line:
Line breakpoint:SimpleClosuresTest
[line: 27] The current scope already
contains a variable of the name fruit
# line 27, column 14.
If i omit 'def' from 'def fruit' Eclipse doesn't complaint and code runs fine.
Could someone explain what is going on with the scopes in both cases?
Thanks.
first a general review of a groovy script:
// file: SomeScript.groovy
x = 1
def x = 2
println x
println this.x
is roughly compiled as:
class SomeScript extends groovy.lang.Script {
def x
def run() {
x = 1
def x = 2
println x // 2
println this.x // 1
}
}
in a groovy script (roughly speaking, a file without the class declaration), assigning a value to an undefined variable is interpreted as a field assignment.
your example tries to defines a closure with a parameter named fruit.
if you defined fruit with the def keyword you get an error message because the name is already taken as a local variable, and you can't duplicate a local variable name.
when you leave the def keyword out, you are actually assigning the value to a field of the class generated for the script, and thus the name fruit can be redefined as a local variable.
regarding scopes, it's pretty much like java...
in the example, you can see x is defined first as a field and then as a variable local to the run() method. there's nothing wrong with that and you can access both the variable and the field.
but once you define a local variable, you cannot create duplicates.
edit --
had to add this before anyone gets me wrong: the translation is not exactly like this (thus the "roughly"). Instead of a field you add a value to the binding of the script, quite like args for commandline scripts or request, session or response for groovlets.
but that is much a longer story...
ok if you really want to know just ask again and i'll explain it better
edit 2 --
i just can't leave it like this, if you ever need more info...
every groovy script has a field named binding, an instance of groovy.lang.Binding or one of its a subclasses.
this binding is basically a map, with methods setVariable and setVariable.
when you omit the def keyword when assigning a value in a script you are actually calling the method setVariable, and when you do something like this.x you are calling the getVariable method.
this is actually because class groovy.lang.Script overrides the methods getProperty and setProperty to call those methods first. that's the reason they behave like fields.
you might have also noticed that there is no type associated to those variables... that's because we are dealing with just a Map inside the binding.
standard groovy scrips are created with an instance of a binding with the args set to the array of parameters.
others, like groovy.servlet.ServletBinding define more variables and behavior, like block the assignment of certain variables, or adding a lazy initialization capabilities...
then the real reason behind the error is... if the def keyword is not used, fruits is not a real variable. still, i believe the behavior is somewhat analog to a field.
sorry about all that.
i was not satisfied with my own oversimplification :S
That String fruit shouldn't be having the same name as your def fruit. (you are defining first a list and then a string with the same name)
def likeIt = { String fruit -> println "I like " + fruit + "s" }
In the second case you are defining the type of the variable with def a posteriori, so it works but it is not a good practice as far as I know.
I think that you don't even need to write ->. The groovy manual says that "The -> token is optional and may be omitted if your Closure definition takes fewer than two parameters", which is the case here.
Second line
String fruit
the same variable name 'fruit' is being used again