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
Related
I try to get names of all trait a class extends using getInterfaces which returns an array of trait's names. When I manually access each member of the array, the method getName returns simple names like this
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
However, when I use map function on arr. The resulting array contains a cryptic version of trait's names
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$1$A, repl$.rs$line$2$B)
The goal of this question is not about how to get the resulting array that contains simple names (for that purpose, I can just use arr.map(t => t.getSimpleName).) What I'm curious about is that why accessing array manually and using a map do not yield a compatible result. Am I wrong to think that both ways are equivalent?
I believe you run things in Scala REPL or Ammonite.
When you define:
trait A
trait B
class C() extends A, B
classes A, B and C aren't defined in top level of root package. REPL creates some isolated environment, compiles the code and loads the results into some inner "anonymous" namespace.
Except this is not true. Where this bytecode was created is reflected in class name. So apparently there was something similar (not necessarily identical) to
// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line$1 sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line$2 sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
which was made because of how scoping works in REPL: new line creates a new scope with previous definitions seen and new added (possibly overshadowing some old definition). This could be achieved by creating a new piece of code as code of new anonymous class, compiling it, reading into classpath, instantiating and importing its content. Byt putting each new line into separate class REPL is able to compile and run things in steps, without waiting for you to tell it that the script is completed and closed.
When you are accessing class names with runtime reflection you are seeing the artifacts of how things are being evaluated. One path might go trough REPLs prettifiers which hide such things, while the other bypass them so you see the raw value as JVM sees it.
The problem is not with map rather with Array, especially its toString method (which is one among the many reasons for not using Array).
Actually, in this case it is even worse since the REPL does some weird things to try to pretty-print Arrays which in this case didn't work well (and, IMHO, just add to the confusion)
You can fix this problem calling mkString directly like:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
However, I would rather suggest just not using Array at all, instead convert it to a proper collection (e.g. List) as soon as possible like:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using Arrays
They are mutable.
Thet are invariant.
They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
Their equals is by reference instead of by value.
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
Hello fellow Scalaists,
I recently took another look at setters in Scala and found out that _ in a method name seems to translate to "There might be a space or not and oh also treat the next special character as part of the method name".
So first of all, is this correct?
Secondly, can someone please explain why the second to last line doesnt work?
class Person() {
private var _name: String = "Hans"
def name = _name
def name_=(aName: String) = _name = aName.toUpperCase
}
val myP = new Person()
myP.name = "test"
myP.name= "test"
myP.name_= "test" //Bad doesnt work
myP.name_=("test")//Now It works
Lastly, removing the getter breaks the above example
class Person() {
private var _name: String = "Hans"
def name_=(aName: String) = _name = aName.toUpperCase
}
val myP = new Person()
myP.name = "test" //Doesnt work anymore
myP.name= "test" //Doesnt work anymore
myP.name_= "test" //Still doesnt work
myP.name_=("test")//Still works
Edit:
Here is a quote(seemingly false) from the source which I originally read, and which spawned this question:
This line is a bit more tricky but I'll explain. First, the method
name is "age_=". The underscore is a special character in Scala and in
this case, allows for a space in the method name which essentially
makes the name "age ="
http://dustinmartin.net/getters-and-setters-in-scala/
So first of all, is this correct?
No, underscores in method names do not work exactly like what you described. It doesn't mean "there might be a space and the character after the space is also part of the method name".
Section 4.2 of the Scala Language Specification explains what a method that has a name that ends with _= means.
A variable declaration var x: T is equivalent to the declarations of both a getter function x and a setter function x_=:
def x: T
def x_= (y: T): Unit
An implementation of a class may define a declared variable using a variable definition, or by defining the corresponding setter and getter methods.
Note that if you only define the setter method and not the getter method, then the magic of the setter method disappears - it's treated as just another method that has a name that happens to end with _=, but this has no special meaning in this case.
Only if there are a getter and setter, the method with _= acts as the setter and can be used as such - that's why myP.name = "test" doesn't work anymore if you remove the getter.
The rules are given in http://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html#identifiers:
First, an identifier can start with a letter which can be followed by an arbitrary sequence of letters and digits. This may be followed by underscore _ characters and another string composed of either letters and digits or of operator characters.
So space isn't allowed after _. (It is actually allowed in identifiers between backquotes.) There are additional special rules for the case where the "string composed of either letters and digits or of operator characters" is precisely =, already described in Jesper's answer.
Secondly, can someone please explain why the second to last line doesnt work?
There are simply no special rules for this case. name_= works here as any other foo method would and you can't write myP.foo "test". But you can write myP foo "test" or myP name_= "test".
I'm trying to decipher somebody else's code. The following appeared in a Scala trait. This isn't its exact content, I flattened out some of the detail to make it more general (it had some extra lines before the closed-curly-bracket incorporating a zipWithIndex method, and some other pattern matching stuff.) My main concern was that I am not familiar with this concept; a value definition that begins with an open-curly-bracket and then a bunch of indented stuff.
val example: ExampleType = {
val anOtherExample = "String"
val yetAnOtherExample = 22
new ExampleType(anOtherExample, yetAnOtherExample)
}
Having experience with C-like languages and/or Java, you may be used to the fact that curly braces {} denote a block of code - i.e. just a set of instructions that will be invoked.
Scala is different on this part, because in Scala almost everything is an expression, i.e. almost everything evaluates to some value and therefore can be assigned to a val, passed as an argument, etc.
Therefore, a block of code in Scala is not just a sequence of instructions, but a valid expression that can be assigned and passed around. Block of code evaluates to the last expression in that block, i.e.
val x: Int = {
doSomething()
doSomethingElse()
42
}
In the above example, x will have 42 assigned as its value.
{
val anotherExample = "String"
val yetAnotherExample = 22
}
This is called block. It is evaluated to its last statement. Here the last statement is an assignment val yetAnotherExample = 22 which is of type Unit in Scala. So your code will not compile if your ExampleType is not the same type as Unit.
i am creating a small scala DSL and running into the following problem to which i dont really have a solution. A small conceptual example of what i want to achieve:
(Compute
write "hello"
read 'name
calc()
calc()
write "hello" + 'name
)
the code defining this dsl is roughly this:
Object Compute extends Compute{
...
implicit def str2Message:Message = ...
}
class Compute{
def write(msg:Message):Compute = ...
def read(s:Symbol):Compute = ...
def calc():Compute = { ... }
}
Now the question: how can i get rid of these parenthesis after calc? is it possible? if so, how? just omitting them in the definition does not help because of compilation errors.
ok, i think, i found an acceptable solution... i now achieved this possible syntax
| write "hello"
| read 'name
| calc
| calc
| write "hello " + 'name
using an object named "|", i am able to write nearly the dsl i wanted. normaly, a ";" is needed after calc if its parameterless. The trick here is to accept the DSL-object itself (here, its the "|" on the next line). making this parameter implicit also allows calc as a last statement in this code.
well, looks like it is definitly not possible to have it the way i want, but this is ok too
It's not possible to get rid of the parenthesis, but you can replace it. For example:
object it
class Compute {
def calc(x: it.type):Compute = { ... }
(Compute
write "hello"
read 'name
calc it
calc it
write "hello" + 'name
)
To expand a bit, whenever Scala sees something like this:
object method
non-reserved-word
It assumes it means object.method(non-reserved-word). Conversely, whenever it sees something like this:
object method object
method2 object2
It assumes these are two independent statements, as in object.method(object); method2.object, expecting method2 to be a new object, and object2 a method.
These assumptions are part of Scala grammar: it is meant to be this way on purpose.
First try to remove the parentheses from the definition of calc. Second try to use curly braces around the whole instead of parentheses. Curly braces and parentheses doesn't mean the same and I find that parenthesis works best in single line code (unless using semi-colons). See also What is the formal difference in Scala between braces and parentheses, and when should they be used?