Abstract value declarations are written by wrapping the name and the type with VAL(...)
:
scala> import treehugger.forest._, definitions._, treehuggerDSL._
import treehugger.forest._
import definitions._
import treehuggerDSL._
scala> val tree = (VAL("foo", IntClass): Tree)
[1m[34mtree[0m: [1m[32mtreehugger.forest.Tree[0m = ValDef(Modifiers(, , Map()),Typed(Ident(foo),TypeTree()),EmptyTree)
scala> treeToString(tree)
[1m[34mres0[0m: [1m[32mString[0m = val foo: Int
or in general:
VAL(sym|"x", typ|"C").tree
where sym
is a symbol and typ
is a type of the value. In the above code, sym|"x"
denotes that either a symbol or String
is accepted as the name of the value, and type|"C"
denotes that either a type or String
is accepted as the type of the value.
Calling tree
method creates a Tree
without a right-hand side (rhs) expression. Because there’s an implicit conversion, forcing VAL(...)
as a Tree
automatically calls tree
method.
Value definitions are written by appending right-hand side tree after :=
as follows:
scala> val tree2 = VAL("foo", IntClass) := LIT(0)
[1m[34mtree2[0m: [1m[32mtreehugger.forest.ValDef[0m = ValDef(Modifiers(, , Map()),Typed(Ident(foo),TypeTree()),Literal(Constant(0)))
scala> treeToString(tree2)
[1m[34mres1[0m: [1m[32mString[0m = val foo: Int = 0
Like Scala, the type annotation can be omitted when rhs is provided:
scala> val tree3 = VAL("foo") := LIT(0)
[1m[34mtree3[0m: [1m[32mtreehugger.forest.ValDef[0m = ValDef(Modifiers(, , Map()),Ident(foo),Literal(Constant(0)))
scala> treeToString(tree3)
[1m[34mres2[0m: [1m[32mString[0m = val foo = 0
In addition, a symbol could be used to define a value instead of using String
names.
scala> object sym {
val foo = RootClass.newValue("foo")
}
defined object sym
scala> val tree4 = VAL(sym.foo) := LIT(0)
[1m[34mtree4[0m: [1m[32mtreehugger.forest.ValDef[0m = ValDef(Modifiers(, , Map()),Ident(foo),Literal(Constant(0)))
scala> treeToString(tree4)
[1m[34mres3[0m: [1m[32mString[0m = val foo = 0
For a larger code base, using symbols makes the code more readable.
The general form of constant value definitions are:
VAL(sym|"x", [typ]) := rhs
Lazy value declarations are written using LAZYVAL(...)
:
scala> val tree5 = (LAZYVAL("foo", IntClass): Tree)
[1m[34mtree5[0m: [1m[32mtreehugger.forest.Tree[0m = ValDef(Modifiers(lazy, , Map()),Typed(Ident(foo),TypeTree()),EmptyTree)
scala> treeToString(tree5)
[1m[34mres4[0m: [1m[32mString[0m = lazy val foo: Int
and lazy value definitions are written as:
scala> val tree6 = LAZYVAL("foo", IntClass) := LIT(0)
[1m[34mtree6[0m: [1m[32mtreehugger.forest.ValDef[0m = ValDef(Modifiers(lazy, , Map()),Typed(Ident(foo),TypeTree()),Literal(Constant(0)))
scala> treeToString(tree6)
[1m[34mres5[0m: [1m[32mString[0m = lazy val foo: Int = 0
Final value definitions are written by appending withFlags(...)
after VAL(...)
:
scala> val tree7 = VAL("foo", IntClass) withFlags(Flags.FINAL) := LIT(0)
[1m[34mtree7[0m: [1m[32mtreehugger.forest.ValDef[0m = ValDef(Modifiers(final, , Map()),Typed(Ident(foo),TypeTree()),Literal(Constant(0)))
scala> treeToString(tree7)
[1m[34mres6[0m: [1m[32mString[0m = final val foo: Int = 0
There is another form of value definitions called pattern values, but it will be discussed later.