The question first: Is the arrow anti pattern the way to do things in Scala?
I've been transitioning from Java to Scala for about 3 months now. I'm starting to see that the anti arrow pattern as a bit of a standard in Scala.
For example, in Java, I like to return from methods as soon as possible. We don't like a lot of inner nestings. If you have lots of them it's called the arrow anti pattern. You can read about it here: http://c2.com/cgi/wiki?ArrowAntiPattern
Java example:
boolean isValid(String input){
if (input.trim().length() <1) return false //return early
if (input.substring(0,3).equals("sth")) return false;
//do some more checks for validity then return true
return true
}
If I wrote this in Scala I'd have to use match-case statements which results in a lot of indenting. Keep in mind that this is just a dummy example where I try to convey only the nesting and indentation of Scala.
def isValid(input:String): Boolean = {
(input.trim.length < 1) match {
case true =>
input.substring(0,3) match {
case sthCase if(sthCase=="sth") =>
//do some more checks etc
//eventually arrive at the "true" branch
... case valid => true
case sthElse if (sthCase=="bla") => //some more code etc
case _ => false
}
case _ => false
}
}
I know this example could have been written the same way I wrote the Java one, but if instead of returning true or false I wanted to assign that value to a variable ie:val valid = (input.trim.length < 1) match ... then this is the only way to do it since you can't reassign to val. I could use var instead of val, but then I'd be using Java instead of Scala.
Question, re-iterated:
So the question is, is the arrow anti pattern the way to do things in Scala or am I missing something? Is there a better way to do in Scala what I just wrote (keeping in mind that I want that match statement result to be assigned to a val variable).
Note that you can always use decomposition in Scala as long as all parts of the code are single entry/single exit. This works because nested functions in Scala can access the local variables of the outer function. E.g.:
def isValid(input: String): Boolean = {
def testLength = input.trim.length >= 1
def testSomething = input.substring(0, 3) == "sth"
return testLength && testSomething
}
You can thus break down any arrow-like structure into its subcomponents as much as you desire.
Note also that using match for testing booleans or comparing something for equality is overkill.
Your java example can easily be translated to an if/else in scala without explicit return and without any additional levels of nesting.
def isValid(input: String) = {
if (input.trim().length() <1) false
else if (input.substring(0,3).equals("sth")) false
else true
}
if/else like everything in scala is an expression and has a return value, so you might as well use it for an assignment:
val isValid =
if (input.trim().length() <1) false
else if (input.substring(0,3).equals("sth")) false
else true
Or in this case you could also simply write
val isValid = (input.trim().length() >= 1) && (!input.substring(0,3).equals("sth"))
If there are too many returns in a function, functions are missing:
def isValid(s: String): Boolean = {
def isLengthValid = s.trim().length() > 0
def shouldNotContainsSomething = s.substring(0, 3) != "sth"
isLengthValid && shouldNotContainsSomething
}
Don't do the cargo cult just because some rule says so. The good thing in Scala is that you can do the best from both worlds -- e.g. sometimes algoritm written in a mutable style is much more clear than the immutable one.
By the way, there is also require method, which is used commonly for fail on validation (but it goes up with an exception).
Related
This question already has answers here:
Return in Scala
(6 answers)
Closed 5 years ago.
how to convert this java code to scala ? Scala doesn't prefer 'return', then scala has a better version ?
public void myMethod(String name){
if(s==null) return;
//other logic and many lines ....
}
Let's do this in two steps:
def myMethod(name: String): Unit =
if(name == null) () else{
//rest of code that works via side-effect
}
The () denotes an instance of Unit.
That's ok but there's something even better! This take advantage that the Option constructor has special null handling, e.g. Option(null) == None.
def myMethod(name: Option[String]): Unit = name.foreach{
//rest of code that works via side-effect
}
Wherein if you might have something which could be null you will make sure that the type system specifies that the variable might or might not contain a value (yes, Java now has Optional too and for similar reasons!)
Or refactor the code in this way:
def myMethod(name: String) = {
if (name != null) {
//other logic and many lines ....
}
}
The short answer is that you don't need to use the return keyword. The return is Scala is pretty much explained here pretty much but I'd like to point out a few things.
Expressions vs. Statements
Most constructs in Java are statements which means they only executed, not evaluated. This is quite important because in Scala most of these constructs are expressions. Let's see how this works on an if-construct.
// Initialize i to 1 if some condition is true otherwise to 0
int i;
if (someCondition) i = 1;
else i = 0;
Assuming we'd like to initialize i in one step (maybe we'd like making it final) we need to use a ternary operator:
final int i = someCondition ? 1 : 0;
This works because the right hand side is actually an expression. Now let's write this in Scala:
val i = if (someCondition) 1 else 0
This is a conditional expression.
Functions
A good thing to keep in mind about functions is that the return value of a function is equal to the result of its last expression. This being you can define the if-expression as the latest in your function and thus its result will be returned. Applying this to your code leaves us with:
def myMethod(name: String): Int = {
if (s == null) -1
else { ... }
}
I've updated your method to return an Int in this case for the sake of argument. You probably need to replace it with something more meaningful. On the else branch you'd also need to return an Int in this case. Anyway I hope this clears your request.
As a closing note this is a nice guide explaining why you should avoid using return. Personally I haven't used it at all even though there are some examples there.
I am a new to Scala coming from Java background, currently confused about the best practice considering Option[T].
I feel like using Option.map is just more functional and beautiful, but this is not a good argument to convince other people. Sometimes, isEmpty check feels more straight forward thus more readable. Is there any objective advantages, or is it just personal preference?
Example:
Variation 1:
someOption.map{ value =>
{
//some lines of code
}
} orElse(foo)
Variation 2:
if(someOption.isEmpty){
foo
} else{
val value = someOption.get
//some lines of code
}
I intentionally excluded the options to use fold or pattern matching. I am simply not pleased by the idea of treating Option as a collection right now, and using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO. But no matter why I dislike these options, I want to keep the scope of this question to be the above two variations as named in the title.
Is there any objective advantages, or is it just personal preference?
I think there's a thin line between objective advantages and personal preference. You cannot make one believe there is an absolute truth to either one.
The biggest advantage one gains from using the monadic nature of Scala constructs is composition. The ability to chain operations together without having to "worry" about the internal value is powerful, not only with Option[T], but also working with Future[T], Try[T], Either[A, B] and going back and forth between them (also see Monad Transformers).
Let's try and see how using predefined methods on Option[T] can help with control flow. For example, consider a case where you have an Option[Int] which you want to multiply only if it's greater than a value, otherwise return -1. In the imperative approach, we get:
val option: Option[Int] = generateOptionValue
var res: Int = if (option.isDefined) {
val value = option.get
if (value > 40) value * 2 else -1
} else -1
Using collections style method on Option, an equivalent would look like:
val result: Int = option
.filter(_ > 40)
.map(_ * 2)
.getOrElse(-1)
Let's now consider a case for composition. Let's say we have an operation which might throw an exception. Additionaly, this operation may or may not yield a value. If it returns a value, we want to query a database with that value, otherwise, return an empty string.
A look at the imperative approach with a try-catch block:
var result: String = _
try {
val maybeResult = dangerousMethod()
if (maybeResult.isDefined) {
result = queryDatabase(maybeResult.get)
} else result = ""
}
catch {
case NonFatal(e) => result = ""
}
Now let's consider using scala.util.Try along with an Option[String] and composing both together:
val result: String = Try(dangerousMethod())
.toOption
.flatten
.map(queryDatabase)
.getOrElse("")
I think this eventually boils down to which one can help you create clear control flow of your operations. Getting used to working with Option[T].map rather than Option[T].get will make your code safer.
To wrap up, I don't believe there's a single truth. I do believe that composition can lead to beautiful, readable, side effect deferring safe code and I'm all for it. I think the best way to show other people what you feel is by giving them examples as we just saw, and letting them feel for themselves the power they can leverage with these sets of tools.
using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO
If you do just want an isEmpty check, isEmpty/isDefined is perfectly fine. But in your case you also want to get the value. And using pattern matching for this is not abuse; it's precisely the basic use-case. Using get allows to very easily make errors like forgetting to check isDefined or making the wrong check:
if(someOption.isEmpty){
val value = someOption.get
//some lines of code
} else{
//some other lines
}
Hopefully testing would catch it, but there's no reason to settle for "hopefully".
Combinators (map and friends) are better than get for the same reason pattern matching is: they don't allow you to make this kind of mistake. Choosing between pattern matching and combinators is a different question. Generally combinators are preferred because they are more composable (as Yuval's answer explains). If you want to do something covered by a single combinator, I'd generally choose them; if you need a combination like map ... getOrElse, or a fold with multi-line branches, it depends on the specific case.
It seems similar to you in case of Option but just consider the case of Future. You will not be able to interact with the future's value after going out of Future monad.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Promise
import scala.util.{Success, Try}
// create a promise which we will complete after sometime
val promise = Promise[String]();
// Now lets consider the future contained in this promise
val future = promise.future;
val byGet = if (!future.value.isEmpty) {
val valTry = future.value.get
valTry match {
case Success(v) => v + " :: Added"
case _ => "DEFAULT :: Added"
}
} else "DEFAULT :: Added"
val byMap = future.map(s => s + " :: Added")
// promise was completed now
promise.complete(Try("PROMISE"))
//Now lets print both values
println(byGet)
// DEFAULT :: Added
println(byMap)
// Success(PROMISE :: Added)
I am new to scala and I am trying to learn it by writing a simple program to check if given a string each open paranthesis has its own closed parenthesis.
For example for the string "{{ssss{{}}}}}" the answer should be false.
The code I am using is the following:
package recfun
import common._
import scala.collection.mutable.Stack
object Main{
def main(args: Array[String]) {
println(balance("{{ssss{{}}}}}".toList))
}
def balance(chars: List[Char]): Boolean = {
val openParentheses : List[Char] = List('(','{','[')
val matchingParentheses = Map(
'}'-> '{',
']'->'[',
')'->'(');
val openParenthesesFound: Stack[Char] = Stack[Char]()
for (letter <- chars) {
if (openParentheses.contains(letter)) openParenthesesFound.push(letter)
else if (matchingParentheses.contains(letter)) {
if (openParenthesesFound.isEmpty || !openParenthesesFound.head.equals(matchingParentheses(letter))) return false
else
openParenthesesFound.pop
}
}
if (openParenthesesFound.nonEmpty) false else true
}
}
However, in the lines
if (openParenthesesFound.isEmpty || !openParenthesesFound.head.equals(matchingParentheses(letter))) return false
else
openParenthesesFound.pop
if I remove "return" as suggested by IntellijIdea the program fails and I get wrong answer: True.
Can anybody help me exaplaining me why it happens so? I am probably missing something.
Also, does anyone have a better solution for this kind of task?
Thank you very much for the help,
Giovanni
Intellij is wrong. Obviously, removing return statement changes the logic of your function.
Perhaps, what it means to tell you is that using return statements in scala is frowned upon in general. It is usually better to come up with a solution avoiding it. Same goes for mutable state actually ...
Something like this is one of the possibilities:
val parens = "{[(" zip "}])" toMap
object OpenP {
def unapply(c: Char) = parens.keys.find(_ == c)
}
object CloseP {
def unapply(c: Char) = parens.values.find(_ == c)
}
#tailrec
def balanced(s: List[Char], ps: List[Char] = Nil): Boolean = (ps, s) match {
case (stack, Nil) => stack.isEmpty
case (p :: stack, CloseP(c) :: tail) => c == parens(p) && balanced(tail, stack)
case (stack, OpenP(p) :: tail) => balanced(tail, p :: stack)
case (stack, c :: tail) => balanced(tail, stack)
}
Your code flow will substantially change depending on whether you use return in the middle of the for comprehension here.
If you use return, your balance method will exit with false the first time you end up in that code path, which seems to be what you want (return false when you encounter the first mismatched parenthesis, since you require that none exist).
If you don't use return, only the containing if-else block will evaluate to false (remember, everything in Scala is an expression) instead of exiting the whole method. Since you aren't assigning it or checking it, your check actually does pretty much nothing, you will loop the whole thing through, and the last statement returns true. So you need the return if you want to solve this problem in this manner.
However, Scala encourages functional programming style without mutable state (such as your Stack here). The simplest way to solve this problem that way would probably be recursion and using an accumulator to store the intermediate parenthesis stack - this way you don't need mutable state (vars or mutable collections). And you avoid using explicit returns (which is encouraged - also probably the reason why your IDE is notifying you about its use) since a method implicitly returns its last statement as its value and this is often simple to achieve with a recursive approach.
I am trying to build a wrapper around data saved in a redis database.
What I want to do is access it as normal as possible as if I have a scala value of some type.
It works, except for comparing it to anything (with == or similar).
So I want to be able to compare it to objects of the inner type.
Best I'll give example code first. This is a rough abstraction of my wrapper:
case class RedisObjectValue[T](name: String, default: T) {
def :=(value: T): Boolean = {
redisMagic.set(name, value)
}
def get: T = {
redisMagic.get[T](name).getOrElse(default)
}
override def equals(o: Any) = o match {
case ov: RedisObjectValue[T] =>
if (this.hashCode() == ov.hashCode()) true // Same reference
else this.get == ov.get
case v =>
// If we don't compare to another RedisObjectValue, let the equals method of data type handle it
this.get.equals(v)
}
}
I have an implicit conversion set up in the companion object so that I can use the wrapper wherever I would use the base type.
object RedisObjectValue {
implicit def objectValueToValue[T](ov: RedisObjectValue[T]): T = {
ov.get
}
}
So, as I said, everything works.
Except the comparing stuff. For that, let's say I have a class Player two values, userId and name.
class Player {
val userId = RedisObjectValue("userId", 0)
val name = RedisObjectValue("player", "Unknown")
}
And now I have a list of players and want to filter to get all players with name "Unknown".
list.filter(_.name == "Unknown")
Which does not work. If I extend the filter filter call and write a function, it tells me in IntelliJ "Comparing unrelated types".
And yeah, I understand what it is telling me, but I want to solve that. I mean I can easily compare Long to Int and similar stuff, so there must be a way to make them comparable, right?
In the code above I have even written the equals function which uses the comparison to the inner type, but it seems like it is not used.
Of course, I can always call .get on the values, like players.filter(_.name.get == "Unknown"), but that's a bit dirty and I would love to avoid that.
EDIT: Found the real problem after some analysis
Old text still above for reading, I will explain the problem here now.
I have a snippet which shows what is not working: https://ideone.com/AmQrkH
The Problem: The RedisObjectValue is defined as Long. When I am comparing it now with
players.filter(_.userId == 2)
for example, it doesn't give any results, even if there are players with userId 2, or to be more exact: 2l.
For direct Long it's not a problem.
players.filter(_._id == 2)
is working.
So is there any fix for that, so that comparable instances of classes to T can also be compared to RedisObjectValue[T], and not just T itself?
Replace this.get.equals(v) with get == v. (Removing this is unrelated, just a good idea in general, the main thing is to use == instead of equals).
Consider this:
scala> 2 equals 2L
res79: Boolean = false
scala> 2 == 2L
res80: Boolean = true
Scala has a language feature to support disjunctions in pattern matching ('Pattern Alternatives'):
x match {
case _: String | _: Int =>
case _ =>
}
However, I often need to trigger an action if the scrutiny satisfies PatternA and PatternB (conjunction.)
I created a pattern combinator '&&' that adds this capability. Three little lines that remind me why I love Scala!
// Splitter to apply two pattern matches on the same scrutiny.
object && {
def unapply[A](a: A) = Some((a, a))
}
// Extractor object matching first character.
object StartsWith {
def unapply(s: String) = s.headOption
}
// Extractor object matching last character.
object EndsWith {
def unapply(s: String) = s.reverse.headOption
}
// Extractor object matching length.
object Length {
def unapply(s: String) = Some(s.length)
}
"foo" match {
case StartsWith('f') && EndsWith('f') => "f.*f"
case StartsWith('f') && EndsWith(e) && Length(3) if "aeiou".contains(e) => "f..[aeiou]"
case _ => "_"
}
Points for discussion
Is there an existing way to do this?
Are there problems with this approach?
Can this approach create any other useful combinators? (for example, Not)
Should such a combinator be added to the standard library?
UPDATE
I've just been asked how the compiler interprets case A && B && C. These are infix operator patterns (Section 8.1.9 of the Scala Reference). You could also express this with standard extract patterns (8.1.7) as &&(&&(A, B), C).' Notice how the expressions are associated left to right, as per normal infix operator method calls likeBoolean#&&inval b = true && false && true`.
I really like this trick. I do not know of any existing way to do this, and I don't foresee any problem with it -- which doesn't mean much, though. I can't think of any way to create a Not.
As for adding it to the standard library... perhaps. But I think it's a bit hard. On the other hand, how about talking Scalaz people into including it? It looks much more like their own bailiwick.
A possible problem with this is the bloated translation that the pattern matcher generates.
Here is the translation of the sample program, generated with scalac -print. Even -optimise fails to simplify the if (true) "_" else throw new MatchError() expressions.
Large pattern matches already generate more bytecode than is legal for a single method, and use of this combinator may amplify that problem.
If && was built into the language, perhaps the translation could be smarter. Alternatively, small improvements to -optimise could help.