#lucastex posted about the Java Elvis operator, and I tried something in Scala to get the same effect.
I've just converted everything to a new Structural Type with the ?: operator taking an object of the same type as argument. So Say:
implicit def toRockStar[B](v : B) = new {
def ?:(opt: => B) = if (v == null) opt else v}
val name: String = "Paulo" // example
Why name ?: "Lucas" gets "Lucas" and name.?:{"Lucas"} gets Paulo? The new Structural Type is supposed to return the initial value of anything if it is not null, that is, "Paulo" in the above code.
I'm a bit confused. Any explanation?
Your operator ends in :, which means it reads right to left when in infix notation. For example:
scala> 1 :: Nil == Nil.::(1)
res2: Boolean = true
All methods read left to right in dot notation, though. So you are actually applying your method to Lucas in the infix notation, and to name in the dot notation.
By the way, the Elvis operator was not accepted for inclusion in Java 7.
For the record (finding this thread while searching back the following article...), Daniel Spiewak (another famous Daniel in the Scala world...) posted an article about Implementing Groovy’s Elvis Operator in Scala.
Related
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'm entirely new to Scala and while reading some tutorials and documentation, I experimented with defining custom control structures.
So I tried to implement an implicit class MyBoolean that provides a ? method with two parameter lists. The first parameter is a block that gets executed if MyBoolean is true, the second gets executed if MyBoolean is false.
Here is an example of how the syntax of the resulting control structure should look like:
true ? {println("true")} {println("false")};
so essentially just a simple if-else statement implemented as a method on Boolean.
Here is my implementation:
object Test extends App {
implicit class MyBoolean(val value: Boolean) {
def ? (body1: => Unit)(body2: => Unit){
if (value) body1;
else body2
}
}
override def main(args: Array[String]): Unit = {
// true ? {println("true")} {println("false")}; //--> compiler error
true.? {println("true")} {println("false")}; // works fine...
}
}
The problem I'm facing is that I get the following compiler error with the intended syntax (in Eclipse):
missing arguments for method ? in class MyBoolean; follow this method
with `_' if you want to treat it as a partially applied function
It only works if I explicitly add the dot . before the method ?.
Shouldn't the dot be optional in Scala when calling methods? Is there anything I'm missing?
Shouldn't the dot be optional in Scala when calling methods?
Sort of, but that's not exactly accurate.
In these cases, that's true:
a.b(c) can be written as a b c
a.b(c, d) can be rewritten as a b (c, d).
From the language spec section 6.12.3, Infix Operations:
The right-hand operand of a left-associative operator may consist of several arguments enclosed in parentheses, e.g. e op e1, …, en. This expression is the interpreted as e.op(e1, …, en).
A left-associative binary operation e1 op e2 is interpreted as e1.op(e2).
But there is no corresponding rule for expressions of the form a.b(c)(d). I'm not really sure why, though. It seems to me that a b {c} {d} would be a perfectly reasonable way to write that.
This is one of the weirdest wrinkles in Scala syntax. You can still use point-free style with multiple argument lists but you have to group the object, method, and first argument list using parentheses (?!)
(true ? {println("true")}) {println("false")}
works just fine.
Why does it work this way? It is rather convenient with the /: and :\ fold symbols; then you can group your first element together with the collection it's supposed to run through.
For everything else it is questionable at best.
Regardless, you're stuck with either parentheses or a dot.
The dot's optional when calling 1-parameter methods, but that syntax doesn't work for a 2-parameter method, even when curried (except as #RexKerr suggests if you bracket it).
You might be able to get it working by doing "manual" currying: write a one-parameter method that returns an object with an apply:
class PartiallyApplied(value: Boolean, body1: => Unit) {
def apply(body2: => Unit) = if (value) body1; else body2
}
class MyBoolean...
def ? (body1: => Unit) = new PartiallyApplied(value, body1)
Scala's <- arrow seems a bit strange. Most operators are implemented somewhere in the source as a function, defined on a data type, either directly or implicitly. <- on the other hand only seems to unusable outside of a for comprehension, where it acts as a syntactic element used to signal the binding of a new variable in a monadic context (via map).
This is the only instance I can think of where Scala has an operator-looking syntactical element that is only usable in a specific context, and isn't an actual function.
Am I wrong about how <- works? Is it a special case symbol used just by the compiler, or is there some way a developer could use this behavior when writing their own code?
For example, would it be possible to write a macro to transform
forRange (i <- 0 to 10) { print(i) }
into
{ var i = 0; while (i <= 10) { print(i) } }
instead of its standard map equivalent? As far as I can tell, any usage of i <- ... outside of a for context causes an exception due to referencing an unknown value.
In short, yes <- is a reserved operator in Scala. It's a compiler thing.
Foreach
There is a strong distinction between foreach and for yield, but the syntax is only syntactic sugar, transformed at compile time.
for (i <- 1 to 10) { statement } expression is translated to:
Range.from(1, 10).foreach(..)
Multiple variables:
for (i <- 1 to 10; y <- 2 to 100) {..} becomes:
Range.from(1, 10).foreach(
el => {Range.from(2, 100).foreach(..)});
With all the variations given by:
for (x <- someList) = someList.foreach(..).
Put simply, they all get de-sugared to foreach statements. The specific foreach being called is given by the collection used.
For yield
The for yield syntax is sugar for flatMap and map. The stay in the monad rule applies here.
for (x <- someList) yield {..} gets translated to a someList.flatMap(..).
Chained operations become hierarchical chains of map/flatMap combos:
for {
x <- someList; y <- SomeOtherList
} yield {} becomes:
someList.flatMap(x => {
y.flatMap(..)
}); and so on.
The point
The point is that the <- operator is nothing more than syntactic sugar to make code more readable, but it always gets replaced at compile time.
To emphasize Rob's point
Rob makes excellent examples of other Scala syntactic sugar.
A context bound
package somepackage;
class Test[T : Manifest] {}
Is actually translated to:
class Test[T](implicit evidence: Manifest[T])
As proof, try to alias a type with a context bound:
type TestAlias[T : Manifest] = somepackage.Test // error, the : syntax can't be used..
It is perhaps easy to see how the : Manifest part is actually not a type a parameter.
It's just easier to type class Test[T : Manifest] rather than class Test[T](implicit evidence: Manifest[T].
The <- operator is a reserved word in the language (see the Scala Language Specification, page 4), but it isn't alone. => is also a reserved word rather than a function. (Also _, :, =, <:, <%, >:, #, and #.) So you couldn't create a function with that name. I don't believe you could adapt it the way you're suggesting, either (though perhaps someone more clever will know a way). You could create a function called `<-` (with surrounding back-ticks), but that would probably be more awkward than it deserves.
As per Scala book, "Programming In Scala" -
Scala is an object-oriented language in pure form: every value is an object and every operation is a method call. For example, when you say 1 + 2 in Scala, you are actually invoking a method named + defined in class Int.
In that sense, what about assignment operation using "=" operator? Is that also a method? Seems unlikely, because then it has to be present in all classes or some common super class (say, java.lang.Object ?) that all classes have to inherit it from. Or is it that not all operations are really method calls in Scala?
A little addition to Jatin answer. There is one case when = can be considered as a method call, but actually it's just a syntactic sugar. In OO part of Scala, where ugly vars lives, you can write the following:
class Test {
private var x0: Int = 0
def x = x0
def x_=(a: Int) = x0 = a
}
Then you can assign new ints to x:
scala> val t = new Test
t: Test = Test#4166d6d3
scala> t.x = 1
t.x: Int = 1
The last line will be desugared into t.x_=(1). I think in this case, considering syntactic sugar, it's possible to say that = is a method call.
Nope. Assignment operator (=) is a reserved word. Also the below are:
_ : = => <- <: <% >: # #
For a more comprehensive list refer § 1.1. Some more information regarding = is described in § 6.12.4.
So yes it is not a method call.
While the other answers are correct for standard Scala, there is a variant called Scala-Virtualized where = and other control structures are method calls.
In the following code :
val expression : String = "1+1";
for (expressionChar <- expression) {
println(expressionChar)
}
the output is "1+1"
How is each character being accessed here ? What is going on behind the scenes in Scala. Using Java I would need to use the .charAt method , but not in Scala, why ?
In scala, a for comprehension:
for (p <- e) dosomething
would be translated to
e.foreach { x => dosomething }
You can look into Scala Reference 6.19 for more details.
However, String in scala is just a Java String, which doesnot have a method foreach.
But there is an implicit conversion defined in Predef which convert String to StringOps which indeed have a foreach method.
So, finally the code for(x <- "abcdef") println(x) be translated to:
Predef.augmentString("abcdef").foreach(x => println(x))
You can look int the scala reference or Scala Views for more information.
scala> for (c <- "1+1") println(c)
1
+
1
Is the same as
scala> "1+1" foreach (c => println(c))
1
+
1
Scalas for-comprehension is not a loop but a composition of higher order functions that operate on the input. The rules on how the for-comprehension is translated by the compiler can be read here.
Furthermore, in Scala Strings are collections. Internally they are just plain old Java Strings for which there exists some implicit conversions to give them the full power of the Scala collection library. But for users they can be seen as collections.
In your example foreach iterates over each element of the string and executes a closure on them (which is the body of the for-comprehension or the argument in the foreach call).
Even more information about for-comprehensions can be found in section 7 of the StackOverflow Scala Tutorial.