I've been shown a weird snippet in Scala which I don't quite understand. To me, assignments in Scala return Unit, unlike in Java where it returns the type of the variable which has been affected a value. However, let's consider this class :
case class C(i: Int) {
def f = C(i = i + 10)
}
This compiles completely fine, which is pretty weird ! The factory method C.apply expects an Int, whereas I pass it what seems to be an assignment, of type Unit. By the way if I remove the assignment to just let the expression, it seems to have the exact same behaviour.
Let's try this now :
case class C(i: Int) {
def f = {
i = i + 10
C(i = i + 10)
}
}
Ok now this is the world I know : i is a val, then you cannot mutate it so i = i + 10 does not compile. However, C(i = i + 10) still compiles without complaining. What is this weirdness ? Is there a reason for thatto exist ?
This is because, in the case of C(i = i + 10) the left-hand i is not the field C#i but a named parameter. No assignment is being done at all.
C(i = i + 10)
^ ^
+---|-------- Parameter name
|
+- - - - - - - - - - - - - - Reference to the field `i`
in the instance of the class `C`
Some places where named parameters make sense:
Avoiding the "what does this {boolean, integer} mean" moment:
someMethod(anObject, flagName=true)
// As opposed to someMethod(anObject, true) ... what's `true` for?
anotherMethod(arg1, arg2, totalMagic=33)
When using default values for parameters (to invoke the right constructor):
def withDefaults(i: Int, flag: Boolean = true, wrapper: Option[String] = None) = {
wrapper.fold(s"$i with $flag")(_.format(i, flag))
}
withDefaults(3, Some("stuff %s around %s"))
// won't compile
// error: type mismatch;
// found : Some[String]
// required: Boolean
withDefaults(3, wrapper = Some("stuff %s around %s"))
// works (returns "stuff 3 around true")
Related
Let's suppose I've defined a macro as below. It essentially types an expression of type T and returns an object of type MyType[T] (the actual types involved don't really matter).
object MyMacro {
def macroImpl[T : context.WeakTypeTag, U : context.WeakTypeTag](context : scala.reflect.macros.blackbox.Context) (expression : context.Expr[T]) : context.Expr[U] =
}
object MyObj {
def callMacro[T](expression : T) : MyType[T] = macro MyMacro.macroImpl[T, MyType[T]]
}
In my macro, I'd like to determine if the expression passed is constant or not. By that I mean, I want to know if the expression, once evaluated at runtime, could ever subsequently evaluate to a different value. If it is constant, I can apply certain optimizations that are very useful.
I know an expression is constant if it is:
a literal expression.
a 'this' expression.
a reference to a val or parameter.
a member invocation where the object expression is constant, and the member being invoked is a val or lazy val.
For example, the expressions passed in the first five calls to callMacro below should be considered a constant:
class MyClass {
val i = 0
val myLiteral = callMacro("Hi!") //constant - literal expression
val myThis = callMacro(this) //constant - this expression
val myInt = callMacro(i) //constant - reference to a val
def myMethod(p : MyOtherClass) {
val myParameter = callMacro(p) //constant - reference to a parameter
val myValMember = callMacro(p.x) //constant - invocation of val member
val myVarMember = vallMacro(p.y) //NOT constant - invocation of var member
val myVarMember = vallMacro(p.z) //NOT constant - invocation of def member
}
}
class MyOtherClass(val x : Int, var y : Int) {
def z = x + y
}
I've already implemented code for the first two cases (which is rather trivial).
def isConstant[T](context : scala.reflect.macros.blackbox.Context) (expression : context.Expr[T]) = {
import context.universe._
expression.tree match {
case This(_) =>
true
case Literal(_) =>
true
/*...put additional cases here...*/
case _ =>
false
}
}
However, I'm not sure whether something like this already exists, or if its even possible to detect whether the member being called on an object is a val or not.
Is it possible to implement the fourth criteria? Or, does anything like this already exist in the API?
I figured out a solution. It basically boiled down to me not knowing about Symbols in scale's reflection system.
I ended up adding a fifth criteria to handle the case in which an implicit parameter or object is referenced.
implicit class extendSymbol(symbol : scala.reflect.macros.blackbox.Context#Symbol) {
def isStable =
(symbol.isTerm && symbol.asTerm.isStable) || (symbol.isMethod && symbol.asMethod.isStable)
}
def isConstant[T](context : scala.reflect.macros.blackbox.Context) (tree : context.Tree) : Boolean = {
import context.universe._
tree match {
case This(_) =>
true
case Literal(_) =>
true
case ident # Ident(_) =>
ident.symbol.isStable
case select # Select(objExpr, term) =>
isConstant(context) (objExpr) && select.symbol.isStable
//for implicit values
case Apply(TypeApply(Select(Select(This(TypeName("scala")), TermName("Predef")), TermName("implicitly")), _), _) =>
true
case _ =>
false
}
}
I found val a = -1 works well in scala REPL, but if I skip the space around the = like val a=-1, the expression doesn't return the result.
Does anyone have ideas about this? Why the space arount the = is necessary here?
=- is a legitimate method name in Scala; the following will work:
class A {
def =-(i: Int) = i
}
val a = new A
a=-1
So the parser can't distinguish your val a=-1 from this case.
val is used in 2 cases:
1) value declaration:
val a = 2
> a: Int = 2
2) pattern definition:
val Some(x) = Some(2)
> x: Int = 2
when you write val a=-1, it clearly fails to match the "value declaration" syntax, so the compiler attempts "pattern definition" syntax.
To see this is the case, let's put a semi-colon in the end of the line.
val a=-1 ;
> <console>:1: error: '=' expected but ';' found.
Indeed, the compiler is looking for the right hand side of pattern definition.
Now notice that =- is a valid identifier name.
So if it is a case class (or a normal class with unapply method), it can be used in pattern
match syntax.
Let's see if this actually works:
case class =- (i: Int, j: Int)
> defined class $eq$minus
val a =- b = =-(2, 3) // infix syntax for pattern match
> a: Int = 2
b: Int = 3
// Yes. it works!
// This is same as:
val =-(a, b) = =-(2, 3)
I am learning currying in scala and trying to apply my knowledge on the following piece of code.
object excercise {
def sqrt2(input : Double) : ((Double, Double) => Double, Double) => Double = {
def iter(guessFxn : (Double, Double) => Double, initial : Double) : Double = {
if (isGoodEnough(initial)) initial
else {
val newGuess: Double = guessFxn(initial, input)
iter(guessFxn, newGuess)
}
}
iter
def isGoodEnough(guess: Double): Boolean = {
math.abs(guess * guess - input ) / input < 0.001
}
}
println(sqrt2(2) ( (g: Double, c: Double) => (g + c / g) / 2, 1))
}
What i want to achieve is that sqrt2 should return a function which takes as 2 arguments
1. fxn(that takes 2 doubles as arg and return a double val) 2. double val
When i am trying to run the worksheet it is giving me error
Error: missing arguments for method iter;
follow this method with `_' if you want to treat it as a partially applied function
iter
^
Error: type mismatch;
found : Unit
required: ((Double, Double) => Double, Double) => Double
}
^
Error: missing arguments for method iter;
follow this method with `_' if you want to treat it as a partially applied function
iter
^
You just have to inverse the order of those piece of codes:
iter
def isGoodEnough(guess: Double): Boolean = {
math.abs(guess * guess - input ) / input < 0.001
}
becomes:
def isGoodEnough(guess: Double): Boolean = {
math.abs(guess * guess - input ) / input < 0.001
}
iter
Indeed, ending with an inner declared method involves a return type of Unit...that's not what you want.
Besides, you had this advice:
follow this method with `_' if you want to treat it as a partially applied function
iter
because as explains before, iter method is not returned (since its call is not made at the end of the method) and thus compiler expects it to be executed.
Of course, to be executed, it needs its compulsory parameters, that you didn't provide.
So the compiler "thinks" that you expected to partially apply the function but badly. Note than a partially applied function is not the same concept than a partial function, that has a different meaning ... ).
It would allow to defer the call, and it's mostly used when dealing standard function (not curried), where we might need to provide only the first parameter and later the following.
Example of partially applied function:
def sum(i: Int, j: Int){...}
calls:
sum 1 _ //just the second parameter needs to be applied later.
sum _ //none parameter is specified, would need to specify both later.
sum 1 2 //complete call, not partially applied so
You can find a good use case of partially applied function here.
I can name objects like this, but can't call m:
object + {
def m (s: String) = println(s)
}
Can't call +.m("hi"):
<console>:1: error: illegal start of simple expression
+.m("hi")
Also can't call + m "hi" (preferred for DSL-usage).
But with object ++ it works fine! Do they conflict with (not existent) unary_+ methods? Is it possible to avoid this?
Indeed it is not possible with unary operators. If you want to call it anyways, you could resort to using the name generated by the compiler for the JVM (which starts with a dollar):
scala> object + {
| def m( s: String ) = println(s)
| }
defined module $plus
scala> +.m("hello")
<console>:1: error: illegal start of simple expression
+.m("hello")
^
scala> $plus.m("hello")
hello
I believe the problem is that in order to handle unary operators without ambiguity, scala relies on a special case: only !, +, - and ~ are treated as unary operators. Thus in +.m("hi"), scala treat + as an unary operator and can't make sense of the whole expression.
Another code using package:
object Operator extends App {
// http://stackoverflow.com/questions/13367122/scalas-infix-notation-with-object-why-not-possible
pkg1.Sample.f
pkg2.Sample.f
}
package pkg1 {
object + {
def m (s: String) = println(s)
}
object Sample {
def f = {
// +.m("hi") => compile error: illegal start of simple expression
// + m "hi" => compile error: expected but string literal found.
$plus.m("hi pkg1")
$plus m "hi pkg1"
}
}
}
package pkg2 {
object + {
def m (s: String) = println(s)
}
object Sample {
def f = {
pkg2.+.m("hi pkg2")
pkg2.+ m "hi pkg2"
pkg2.$plus.m("hi pkg2")
pkg2.$plus m "hi pkg2"
}
}
}
java version "1.7.0_09"
Scala code runner version 2.9.2
I'm trying to write a performance measurements library for Scala. My idea is to transparently 'mark' sections so that the execution time can be collected. Unfortunately I wasn't able to bend the compiler to my will.
An admittedly contrived example of what I have in mind:
// generate a timing function
val myTimer = mkTimer('myTimer)
// see how the timing function returns the right type depending on the
// type of the function it is passed to it
val act = actor {
loop {
receive {
case 'Int =>
val calc = myTimer { (1 to 100000).sum }
val result = calc + 10 // calc must be Int
self reply (result)
case 'String =>
val calc = myTimer { (1 to 100000).mkString }
val result = calc + " String" // calc must be String
self reply (result)
}
Now, this is the farthest I got:
trait Timing {
def time[T <: Any](name: Symbol)(op: => T) :T = {
val start = System.nanoTime
val result = op
val elapsed = System.nanoTime - start
println(name + ": " + elapsed)
result
}
def mkTimer[T <: Any](name: Symbol) : (() => T) => () => T = {
type c = () => T
time(name)(_ : c)
}
}
Using the time function directly works and the compiler correctly uses the return type of the anonymous function to type the 'time' function:
val bigString = time('timerBigString) {
(1 to 100000).mkString("-")
}
println (bigString)
Great as it seems, this pattern has a number of shortcomings:
forces the user to reuse the same symbol at each invocation
makes it more difficult to do more advanced stuff like predefined project-level timers
does not allow the library to initialize once a data structure for 'timerBigString
So here it comes mkTimer, that would allow me to partially apply the time function and reuse it. I use mkTimer like this:
val myTimer = mkTimer('aTimer)
val myString= myTimer {
(1 to 100000).mkString("-")
}
println (myString)
But I get a compiler error:
error: type mismatch;
found : String
required: () => Nothing
(1 to 100000).mkString("-")
I get the same error if I inline the currying:
val timerBigString = time('timerBigString) _
val bigString = timerBigString {
(1 to 100000).mkString("-")
}
println (bigString)
This works if I do val timerBigString = time('timerBigString) (_: String), but this is not what I want. I'd like to defer typing of the partially applied function until application.
I conclude that the compiler is deciding the return type of the partial function when I first create it, chosing "Nothing" because it can't make a better informed choice.
So I guess what I'm looking for is a sort of late-binding of the partially applied function. Is there any way to do this? Or maybe is there a completely different path I could follow?
Well, thanks for reading this far
-teo
The usual pattern when you want "lazy" generics is to use a class with an apply method
class Timer(name: Symbol) {
def apply[T](op: => T) = time(name)(op)
}
def mkTimer(name: Symbol) = new Timer(name)