I am a Scala newbie and one thing that I find very strange is the error
";" or new line expected
for example the class Point definition in Tour of scala section Private Members and Getter/Setter Syntax
if I write the code like this
def x_ = (newValue : Int): Unit = {}
I will get the ; or new line expected and it does not recognise newLine . Note the space after x_. and if I write it without the space like this
def x_= (newValue : Int): Unit = {}
the mentioned errors disappear?!
Why is that? is this something to do with the scala language or is it to do with intellij ide. If it has something to do with the language then why don't I get the error in this definition
def x = _x
Whitespace is not allowed in identifiers, so
def x_ = = 42
is not allowed for the same reason why
def hello_ world = 42
is not allowed. If you want whitespace in an identifier, then surround it with backquotes
scala> def `x_ =` = 42
def x_$u0020$eq: Int
scala> `x_ =`
val res0: Int = 42
scala> def `hello_ world` = 42
def hello_$u0020world: Int
scala> `hello_ world`
val res1: Int = 42
The identifier x_= has no whitespace so the following is legal
scala> def x_= = 42
def x_$eq: Int
scala> x_=
val res2: Int = 42
Not how the two = in def x_= = 42 are semantically different
def x_= = 42
| |
part of identifier body follows
The answer (as you have discovered) is that _= is treated specially at the end of a method name. (See the spec)
So this is valid
def x_= (newValue : Int): Unit = {}
but this is not
def x= (newValue : Int): Unit = {}
and neither is this
def x_=x (newValue : Int): Unit = {}
In fact section 1.1 of the spec says that there can be any op after an _, so these are also valid:
def x_#(newValue : Int): Unit = {}
def x_+-*/(newValue : Int): Unit = {}
def x_???(newValue : Int): Unit = {}
Related
For Scala 3 macros, does anyone know of a way to find all functions with a given annotation?
For instance:
#fruit
def apple(): Int = ???
#fruit
def banana(): Int = ???
#fruit
def coconut(): Int = ???
#fruit
def durian(): Int = ???
def elephant(): Int = ???
#fruit
def fig(): Int = ???
I would want to find a list of apple, banana, coconut, durian, fig. They could be defined anywhere, but in my case they will all be in a single package.
This solution will extract all the definitions with some annotation from a given package. I will leverage also the compile-time reflection.
This solution will extract all the definitions with some annotations from a given package. I will also leverage the compile-time reflection.
So, To solve your problem, we need to divide it in:
methods gathering from a package;
filter only methods with a given annotation;
transform symbols in function application.
I suppose that you can pass the package and the annotation (and also the return type) as a type argument. So the macro signature is something like that:
inline def findAllFunction[P, A <: ConstantAnnotation, R]: List[() => R] =
${Implementation.myMacroImpl[P, A, R]()}
The first point is straightforward. we could extract all the methods defined as:
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
The second point is also quite easy. Symbol class has the method hasAnnotation that could be used in this case:
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
The last point is a little bit challenging. Here we should construct the method call. So we need to create the AST that correspond to the method call. Inspired by this example, we can call definition using Apply. Select and This serve to select the correct method that will be called:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
Here I used lamba call, if you want to return directly the value you should change the last two instructions:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => apply.asExprOf[R])
Expr.ofList(appliedDef)
To sum up, the all methods could be defined as:
def myMacroImpl[P: Type, A: Type, R: Type]()(using
Quotes
): Expr[List[() => R]] = {
import quotes.reflect.*
val annotation = TypeRepr.of[A].typeSymbol
val moduleTarget = TypeRepr.of[P].typeSymbol
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
def transformToFunctionApplication(
methods: List[Symbol]
): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
val methods = methodsFromPackage(moduleTarget)
val annotatedMethod = methodsAnnotatatedWith(methods, annotation)
transformToFunctionApplication(annotatedMethod)
}
Finally, you can use the macro as:
package org.tests
import org.tests.Macros.fruit
package foo {
#fruit
def check(): Int = 10
#fruit
def other(): Int = 11
}
#main def hello: Unit =
println("Hello world!")
println(Macros.findAllFunction[org.tests.foo, fruit, Int].map(_.apply())) /// List(10, 11)
Scastie
In scala def is used to define a method and val, var are used for defining variables.
Consider the following code:
scala> def i = 3
i: Int
scala> i.getClass()
res0: Class[Int] = int
scala> val v = 2
v: Int = 2
scala> v.getClass()
res1: Class[Int] = int
scala> println(v)
2
scala> println(i)
3
scala> i+v
res4: Int = 5
scala> def o = () => 2+3
o: () => Int
scala> o.getClass()
res5: Class[_ <: () => Int] = class $$Lambda$1139/1753607449
Why does variable definition work using def? If it is defining a function that returns an Int then why does getClass show Int instead of a function object?
Unlike val or var declaration, def i = 3 is not variable declaration. You are defining a method/function which returns a constant 3 and i does not take any parameters.
declaration using val and var get evaluated immediately but in case of lazy val and def evaluation happens when called explicitly.
i is a not argument function. In order to get rid of confusion you could declare it using empty parenthesis as well
def i() = 3
Difference between lazy val and def is
lazy val is lazily evaluated and the result is cached. That means further
def declaration is evaluated every time you call method name.
Example using Scala REPL
scala> lazy val a = { println("a evaluated"); 1}
a: Int = <lazy>
scala> def i = { println("i function evaluated"); 2}
i: Int
scala> a
a evaluated
res0: Int = 1
scala> a
res1: Int = 1
scala> a
res2: Int = 1
scala> i
i function evaluated
res3: Int = 2
scala> i
i function evaluated
res4: Int = 2
scala> i
i function evaluated
res5: Int = 2
Notice that a is evaluated only once and further invocations of a return the cached result i.e lazy val is evaluated once when it is called and the result is stored forever. So you see println output once
Notice function is evaluated every time it is invoked. In this case you see println output every time you invoke the function
General Convention
There's a convention of using an empty parameter list when the method has side effects and leaving them off when its pure.
edited
scala> def i = 1
i: Int
scala> :type i
Int
scala> :type i _
() => Int
EDIT: My answer addresses the question of revision #3.
It is quite useful to look on the code in the middle of the compilation process where you can look on what your code is actually translated to. The following simple program:
object TestApp {
def definedVal = 3
val valVal = 3
lazy val lazyValVal = 3
def main(args: Array[String]) {
println(definedVal)
println(valVal)
println(lazyValVal)
}
}
is translated to the following (using -Xprint:mixin compiler option):
[[syntax trees at end of mixin]] // test.scala
package <empty> {
object TestApp extends Object {
#volatile private[this] var bitmap$0: Boolean = false;
private def lazyValVal$lzycompute(): Int = {
{
TestApp.this.synchronized({
if (TestApp.this.bitmap$0.unary_!())
{
TestApp.this.lazyValVal = 3;
TestApp.this.bitmap$0 = true;
()
};
scala.runtime.BoxedUnit.UNIT
});
()
};
TestApp.this.lazyValVal
};
def definedVal(): Int = 3;
private[this] val valVal: Int = _;
<stable> <accessor> def valVal(): Int = TestApp.this.valVal;
lazy private[this] var lazyValVal: Int = _;
<stable> <accessor> lazy def lazyValVal(): Int = if (TestApp.this.bitmap$0.unary_!())
TestApp.this.lazyValVal$lzycompute()
else
TestApp.this.lazyValVal;
def main(args: Array[String]): Unit = {
scala.this.Predef.println(scala.Int.box(TestApp.this.definedVal()));
scala.this.Predef.println(scala.Int.box(TestApp.this.valVal()));
scala.this.Predef.println(scala.Int.box(TestApp.this.lazyValVal()))
};
def <init>(): TestApp.type = {
TestApp.super.<init>();
TestApp.this.valVal = 3;
()
}
}
}
From the output above it is possible to conclude the following:
definedVal is actually a method.
valVal is a field which is initialized in the constructor and has an automatically generated accessor.
For the lazy field lazyValVal compiler generates compute method which is called only once when the field is accessed the first time.
There is few different concept. Call by name, call by value and call by need. All def is essentially calls by name. What do you mean variable definition using def ??
Looks like duplicate to me:
Call by name vs call by value in Scala, clarification needed
More details in wiki: https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name
I am Scala beginner. Below Scala code runs well, but I cannot understand it. Log shows, line 19 finally run to line 12. How could it be?
object TestClassDef {
class Person {
private var _age = 0
def age:Int = _age
def age_=(newAge: Int) = {
_age = newAge
println("age changed to " + _age) // line 12
}
}
def main(args: Array[String]) {
var p = new Person()
// p.age_=(25)
p.age = 26 // line 19
}
}
If I get your question correctly, you're surprised that the method is called when you assign the value on line 19. This is because the _= (at the end of the age function with an Int parameter) means that it's an assignment operator (also see What are all the uses of an underscore in Scala?) so it does make sense that it's called when you simply type p.age = 26.
This is mutator
def age_=(newAge: Int) = {
_age = newAge
println("age changed to " + _age)
}
So the call
p.age = 26
is converted by compiler to
p.age_=(26)
which makes call to mutator.
Mutator naming conventions from http://docs.scala-lang.org/style/naming-conventions.html
For mutators, the name of the method should be the name of the property with “_=” appended. As long as a corresponding accessor with that particular property name is defined on the enclosing type, this convention will enable a call-site mutation syntax which mirrors assignment. Note that this is not just a convention but a requirement of the language.
Also to see what compiler is creating pass -Xprint:typer to the Scala compiler. For reference the above code with this parameter generates:
package <empty> {
object TestClassDef extends scala.AnyRef {
def <init>(): TestClassDef.type = {
TestClassDef.super.<init>();
()
};
class Person extends scala.AnyRef {
def <init>(): TestClassDef.Person = {
Person.super.<init>();
()
};
private[this] var _age: Int = 0;
<accessor> private def _age: Int = Person.this._age;
<accessor> private def _age_=(x$1: Int): Unit = Person.this._age = x$1;
def age: Int = Person.this._age;
def age_=(newAge: Int): Unit = {
Person.this._age_=(newAge);
scala.this.Predef.println("age changed to ".+(Person.this._age))
}
};
def main(args: Array[String]): Unit = {
var p: TestClassDef.Person = new TestClassDef.this.Person();
p.age_=(26)
}
}
}
Scala allows non-alphanumerics in identifiers (in two ways):
case 1:
(specialcharacters)*
scala> val ##*# = 1000000
scala> val #Alpha# = 1 // mixing alphanumerics not allowed
case 2:
letter(alphanumerics)* _ (specialcharacters)*
scala> val k12? = 1 // doesn't work, _ is mandatory
scala> val k12_? = 1
scala> val k12_?*&^% = 1
scala> val k12_?Alpha = 1 // doesn't work, can't mix alphanumeric
Special cases:
Some symbols/combination-of-symbols are reserved e.g. = # <%
scala> val # = 1 // doesn't work
scala> val ### = 1 // works fine
scala> val <% = 1 // doesn't work
scala> val <%> = 1 // works fine
Some symbol-combinations are special, _= can be used in method names but not in variable names.
scala> val k_= = 1 // doesn't work
scala> def k_= = 1 // works fine
method names ending in _= are setters.
if a class/object's setter method def x_= is defined along with a parameter-less method of same name def x, then x = e is interpreted as x_=(e)
def createFloatBuffer(data: Option[Quaternion]*): Option[FloatBuffer] = data match {
...
}
def createFloatBuffer(data: Option[Vector3f]*): Option[FloatBuffer] = data match {
...
}
This code will not compile due to the two methods having the same method signature. None type would not know which method to call.
I could just rename the methods, however I would like to this overloading style in my code.
After type erasure this two methods become createFloatBuffer(data: Option), and all types information is lost and not available at run time.
As a workaround I can suggest you to use TypeClass pattern.
case class Quaternion(v: Int)
case class Vector3f(v: Int)
case class FloatBuffer(v: Int)
sealed trait FloatBufferBuilder[T] {
def createFloatBuffer(data: Option[T]): Option[FloatBuffer]
}
implicit object QuaternionFloatBufferBuilder extends FloatBufferBuilder[Quaternion] {
def createFloatBuffer(data: Option[Quaternion]) = data.map(d => FloatBuffer(d.v))
}
implicit object Vector3fFloatBufferBuilder extends FloatBufferBuilder[Vector3f] {
def createFloatBuffer(data: Option[Vector3f]) = data.map(d => FloatBuffer(d.v))
}
def createFloatBuffer[T : FloatBufferBuilder](data: Option[T]): Option[FloatBuffer] =
implicitly[FloatBufferBuilder[T]].createFloatBuffer(data)
println(createFloatBuffer(Some(Quaternion(1))))
println(createFloatBuffer(Some(Vector3f(1))))
Magnet Pattern could also interesting for you: http://spray.io/blog/2012-12-13-the-magnet-pattern/
This is the use case for:
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
<console>:10: error: double definition:
def f(is: Int*): Int at line 10 and
def f(ds: Double*): Int at line 10
have same type after erasure: (is: Seq)Int
object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
^
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*)(implicit dummy: DummyImplicit) = 43 }
defined object X
scala> X f 1
res2: Int = 42
scala> X f 1.0
res3: Int = 43
Inspired by this, I was wondering if we can have type-safe string interpolations in Scala (maybe using macros)?
For example, I want to have something like this
def a[A] = ???
val greetFormat = f"Hi! My name is ${a[String]}. I am ${a[Int]} years old"
greetFormat.format("Rick", 27) // compiles
//greetFormat.format("Rick", false) // does not compile
//greetFormat.format(27, "Rick") // does not compile
//greetFormat.format("Rick", 27, false) // does not compile
//greetFormat.format("Rick") // does not compile or is curried?
The f string interpolator is already implemented with a macro.
This can be demonstrated inside of the REPL:
scala> val b = "not a number"
b: String = not a number
scala> f"$b%02d"
<console>:9: error: type mismatch;
found : String
required: Int
f"$b%02d"
^
Just wrap it in a function.
def greet(name: String, age: Int) = s"Hi! My name is $name. I am $age years old"
You can supply implicits to the f-interpolator:
scala> case class A(i: Int)
defined class A
scala> implicit def atoi(a: A): Int = a.i
warning: there were 1 feature warning(s); re-run with -feature for details
atoi: (a: A)Int
scala> f"${A(42)}%02d"
res5: String = 42
See also Travis Brown's examples and solution for using regex group names in extractions. It took me about a minute to steal that great idea.
"a123bc" match {
case res # xr"(?<c>a)(?<n>\d+)(?<s>bc)" => assert {
res.c == 'a' && res.n == 123 && res.s == "bc"
}
}
For the record, on the composition side, I would like:
val a = A(Rick, 42)
val greeter = f"Hi! My name is $_. I am ${_}%d years old"
greeter(a, a)
But it was deemed too much for the poor underscore. You'll have to write the function as in the other answer.
Your form, in which your macro sees "${a[Int]}" and writes a function with an Int param, doesn't look hard to implement.
Other features of the f-interpolator include other static error checking:
scala> f"$b%.02d"
<console>:19: error: precision not allowed
f"$b%.02d"
^
and support for Formattable:
scala> val ff = new Formattable { def formatTo(fmtr: Formatter, flags: Int, width: Int, precision: Int) = fmtr.format("%s","hello, world") }
ff: java.util.Formattable = $anon$1#d2e6b0b
scala> f"$ff"
res6: String = hello, world
A quick macro might emit (i: Int) => f"${ new Formattable {...} }".