Why do people use _? as an identifier suffix? - scala

I start reading Lift framework source code, I find that there're so many methods are defined using a name like methodName_? , is there a convention that _? has some special meaning?
def empty_? : Boolean = {}

You're unlikely to see the construct outside of the lift framework; I suspect that it's mostly Ruby-envy.
Almost any other Scala project will shy away from this syntax. Not because of the trailing question mark, but because it's yet another way to introduce underscores into your code - and the symbol is already far too heavily overloaded.
Based on an evaluation of multiple Scala projects, the notation can be reasonably described as non-idiomatic.
UPDATE
The reason that the underscore is required is to disambiguate from infix notation, in which:
x?y
would be read as
x.?(y)
with ? being a method name. Whereas:
x_?y
Clearly demarks x_? as being atomic.
The syntax is an example of what is formally known as a "mixed identifier", and is intended to allow definitions such as
def prop_=(v:String) = ... //setter
def unary_- = ... //prefix negation operator
It could (arguably) be considered a hack when similar construct is used simply to shove a question mark at the end of a method name.

The ? denotes that this is a predicate, a function returning Boolean. This convention goes back to Lisp, where ? (Scheme), p or -p (other Lisps, simulating the question mark with a "similar" letter) also denote predicates. Think of it as asking a question, "is the object empty?"
Scala will only allow mixed identifier names (containing alphanumerics and punctuation) if you separate them by _. E.g.,
scala> def iszero?(x : Int) = x == 0
<console>:1: error: '=' expected but identifier found.
def iszero?(x : Int) = x == 0
^
doesn't work, but
scala> def iszero_?(x : Int) = x == 0
iszero_$qmark: (x: Int)Boolean
does.

Related

Rounding numeric parameter types in Scala

I'm experimenting with a method in Scala which is attempting to round numbers depending on how big they are, e.g. if the value is below 1 then it makes sense to round it by at least one decimal point; rather than remaining an integer. Here's what I'm trying:
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = num match {
case num if num < 1 => numeric.toDouble(num)
case _ => numeric.toInt(num)
}
Which throws this error:
value < is not a member of type parameter A
Of course the parameters need to accept a range of parameter types within the function signature as it may be taking integers or doubles so this has added a further complexity.
I've taken the conditional statement on the first case from this answer -
Using comparison operators in Scala's pattern matching system and am eager to use a Functional Programming approach. Perhaps there is also some in-built scala function like Math.round() that could help to round the second condition rather than remove any decimals. Thanks!
TL;DR : every numeric methods you'll need are inside numeric
The error is self-explanatory: your type A (which is generic) does not have a < method.
However, what you have is a typeclass with all numeric methods in it, so you should probably import them:
import numeric._
This imports (among other things) implicit conversion to OrderingOps, which has the desired method. But this comparison cannot work, since 1 is not an A, it's an Int!
The solution is simply to use fromIntof numeric.
While we're at it, you will have unexpected results for input such as -234.2e123... You'd better do your test on the absolute value of your number (abs is also a method of numeric).
Also, if you want to do a simple test, there is no need to use pattern matching, a if else statement is enough
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = {
import numeric._
if (abs(num) < fromInt(1)) toDouble(num) else toInt(num)
}

Get a different result when calling the same function

I am a scala newbie.
This is my code. The results of two types of same method use are different,
can anyone explain to me why???
The thing is that in Scala, all functions ( or "operators") which have names ending with a colon ':' are deemed as right associative when used with infix notation.
So... for your function,
def ::(t: TG) = ???
When, you are writing
val lxx3 = lxx1 :: lxx2
The function :: associates to the right (ie. with lxx2). So it is actually equivalent to
val lxx3 = lxx2.::(lxx1)
instead of this,
val lxx3 = lxx1.::(lxx2)

How to annotate types of expressions within a Scala for expression

I'm wondering how to (safely) add type ascriptions to the lefthand side of Scala for expressions.
When working with complex for expressions, the inferred types are often hard to follow, or can go off track, and it's desirable to annotate the expressions within the for {..} block, to check that you and the compiler agree. An illustrative code sketch that uses the Eff monad:
for {
e1: Option[(Int, Vector[Int])] <- complexCalc
e2 <- process(e1)
} yield e2
def complexCalc[E]: Eff[E, Option[(Int, Vector[Int])]] = ???
However, this conflicts with Scala's support for pattern matching on the LHS of a for-expression.
As discussed in an earlier question, Scala treats the type ascription : Option[(Int, Vector[Int])] as a pattern to be matched.
The compiler has the concept of irrefutable patterns, which always match. Conversely, a refutable pattern might not match, and so when used in for expression, the righthand-side expression must provide a withFilter method to handle the non-matching case.
Due to a longstanding compiler bug/limitation, tuples and other common constructor patterns seem never to be treated as irrefutable.
The net result is that adding a type ascription makes the LHS pattern seem refutable and requires a filter op to be defined on the RHS. A symptom is compiler errors like value filter is not a member of org.atnos.eff.Eff[E,Option[(Int, Vector[Int])]].
If there any syntactic form that can be used to ascribe types to the intermediate expressions containing tuples, within for expressions, without encountering refutable pattern matching?
Turns out there's extensive discussion of this problem, and the current best solution, in this Scalaz PR *.
The work around is to add the type ascription in an assignment on the line below:
for {
e <- complexCalc
e1: Option[(Int, Vector[Int])] = e
e2 <- process(e1)
} yield e2
def complexCalc[E]: Eff[E, Option[(Int, Vector[Int])]] = ???

How to systematically avoid unsafe pattern matching in Scala?

Consider the following broken function:
def sum (list : Seq[Int]) : Int = list match {
case Nil => 0
case head :: tail => head + sum(tail)
}
Here, the function was supposed to work with a List[Int], but was refactored to accept Seq[Int] instead, thus becoming broken without the compiler noticing.
This gaping hole in Scala's incomplete pattern match detection makes it next to useless.
I want to have a way of systematically detecting such problems. Specifically, I'd like the compiler to emit an error/warning on every instanceof-guided pattern match, i.e. I only want to allow pattern matches on sealed hierarchies and on custom matchers.
Are there existing compiler options/plugins for doing conservative (as opposed to arbitrary) checks of pattern matching safety?
Have a look at this answer by M. Odersky.
Summary
Checks on matches of non-sealed hierarchies are doable, not trivial and not (yet) implemented.
Nil and :: are clearly ways to construct a List, but not all Sequences happen to be Lists, so one would expect the Scala type checker to reject this program as ill-typed. Right?
Wrong. Try this and you'll see what I mean:
def sum (list : Seq[Int]) : Int = list match {
case Nil => 0
case head :: tail => head + sum(tail)
case _ => -1
}
> sum(Array(1,2,3).toSeq)
res1: Int = -1
> sum(List(1,2,3))
res2: Int = 6
So you see, some Sequences might be able to be deconstructed with Nil and ::, so those which can, will. Those which can't will fail the pattern match and move on, trying the next match. Nil and :: are sufficient to cover all the possibilities for List, but not for Seq. There is a tradeoff here between subtyping, convenience, and type safety. The solution for now is: be more careful when you refactor.

When to use parenthesis in Scala infix notation

When programming in Scala, I do more and more functional stuff. However, when using infix notation it is hard to tell when you need parenthesis and when you don't.
For example the following piece of code:
def caesar(k:Int)(c:Char) = c match {
case c if c isLower => ('a'+((c-'a'+k)%26)).toChar
case c if c isUpper => ('A'+((c-'A'+k)%26)).toChar
case _ => c
}
def encrypt(file:String,k:Int) = (fromFile(file) mkString) map caesar(k)_
The (fromFile(file) mkString) needs parenthesis in order to compile. When removed I get the following error:
Caesar.scala:24: error: not found: value map
def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
^
one error found
mkString obviously returns a string on which (by implicit conversion AFAIK)I can use the map function.
Why does this particular case needs parentheses? Is there a general guideline on when and why you need it?
This is what I put together for myself after reading the spec:
Any method which takes a single parameter can be used as an infix operator: a.m(b) can be written a m b.
Any method which does not require a parameter can be used as a postfix operator: a.m can be written a m.
For instance a.##(b) can be written a ## b and a.! can be written a!
Postfix operators have lower precedence than infix operators, so foo bar baz means foo.bar(baz) while foo bar baz bam means (foo.bar(baz)).bam and foo bar baz bam bim means (foo.bar(baz)).bam(bim).
Also given a parameterless method m of object a, a.m.m is valid but a m m is not as it would parse as exp1 op exp2.
Because there is a version of mkString that takes a single parameter it will be seen as an infix opertor in fromFile(file) mkString map caesar(k)_. There is also a version of mkString that takes no parameter which can be used a as postfix operator:
scala> List(1,2) mkString
res1: String = 12
scala> List(1,2) mkString "a"
res2: String = 1a2
Sometime by adding dot in the right location, you can get the precedence you need, e.g. fromFile(file).mkString map { }
And all that precedence thing happens before typing and other phases, so even though list mkString map function makes no sense as list.mkString(map).function, this is how it will be parsed.
The Scala reference mentions (6.12.3: Prefix, Infix, and Postfix Operations)
In a sequence of consecutive type infix operations t0 op1 t1 op2 . . .opn tn, all operators op1, . . . , opn must have the same associativity.
If they are all left-associative, the sequence is interpreted as (. . . (t0 op1 t1) op2 . . .) opn tn.
In your case, 'map' isn't a term for the operator 'mkstring', so you need grouping (with the parenthesis around 'fromFile(file) mkString')
Actually, Matt R comments:
It's not really an associativity issue, more that "Postfix operators always have lower precedence than infix operators. E.g. e1 op1 e2 op2 is always equivalent to (e1 op1 e2) op2". (Also from 6.12.3)
huynhjl's answer (upvoted) gives more details, and Mark Bush's answer (also upvoted) point to "A Tour of Scala: Operators" to illustrate that "Any method which takes a single parameter can be used as an infix operator".
Here's a simple rule: never used postfix operators. If you do, put the whole expression ending with the postfix operator inside parenthesis.
In fact, starting with Scala 2.10.0, doing that will generate a warning by default.
For good measure, you might want to move the postfix operator out, and use dot notation for it. For example:
(fromFile(file)).mkString map caesar(k)_
Or, even more simply,
fromFile(file).mkString map caesar(k)_
On the other hand, pay attention to the methods where you can supply an empty parenthesis to turn them into infix:
fromFile(file) mkString () map caesar(k)_
The spec doesn't make it clear, but my experience and experimentation has shown that the Scala compiler will always try to treat method calls using infix notation as infix operators. Even though your use of mkString is postfix, the compiler tries to interpret it as infix and so is trying to interpret "map" as its argument. All uses of postfix operators must either be immediately followed by an expression terminator or be used with "dot" notation for the compiler to see it as such.
You can get a hint of this (although it's not spelled out) in A Tour of Scala: Operators.