Suppose an outer class with an inner composite of two inner classes:
class Outer(val times: Int) {
class Inner(val count: Int)
object Inner {
def apply(i: Int) = new Inner(i)
}
class InnerWrap(val i: Inner)
object InnerWrap {
def apply(i: Inner) = new InnerWrap(i)
}
def method(i: Inner) = i.count * times
}
object Outer {
def apply(times: Int) = new Outer(times)
}
class PathDependentExpl {
val o = new Outer(3)
val i = o.Inner(2)
val p = new Outer(5)
val j = p.Inner(3)
println(o.method(i))
println(p.method(j))
}
All nice and dandy. We even have compiler protection against feeding inners from one Outer to methods of another Outer through path-dependent types.
But the syntax is a little annoying. I want to be able to write something like
implicit val p = new Outer(5)
val k = Inner(3) // same as p.Inner(3)
val l = InnerWrap(Inner(3))
...omitting the outer instance for the block where the implicit is valid. So I rush adding delegate methods with the Outer object as an implicit parameter.
object Outer {
def apply(times: Int) = new Outer(times)
def Inner(c: Int)(implicit o: Outer) = o.Inner(c)
def InnerWrap(i: o.Inner)(implicit o: Outer) = o.InnerWrap(i)
}
That last InnerWrap definition yields: "illegal dependent method type: parameter appears in the type of another parameter in the same section or an earlier one", which actually makes sense. I tried def InnerWrap[O <: Outer#Inner](i: O)(implicit o: Outer) = o.InnerWrap(i) and other variants to no avail.
Question is, how can I still get to use the cleaner syntax? How can the declaration of InnerWrap in object Outer can be made to accept o.Inners or equivalent?
As I noted in a comment above, it's possible to import the objects (or methods) you need from p, which may give you the clean syntax you're looking for:
scala> val p = new Outer(5)
p: Outer = Outer#4fe2fe5d
scala> import p._
import p._
scala> val k = Inner(3)
k: p.Inner = Outer$Inner#b90ffa7
scala> val l = InnerWrap(Inner(3))
l: p.InnerWrap = Outer$InnerWrap#3bd6bff7
Related
I'm looking to design a DSL in Scala that has the least amount of syntax cruft possible. It's meant to be used by users who don't know Scala, but can take advantage of Scala type system for validation and error checking. In my head the DSL looks like this:
outer {
inner(id = "asdf") {
value("v1")
value("v2")
}
}
This snipped should produce a value like this:
Outer(Inner("asdf", Value("v1") :: Value("v2") :: Nil))
Given data structures
case class Outer(inner: Inner)
case class Inner(values: List[Value])
case class Value(value: String)
The idea is that inner function is only available in the closure following outer, value function is only available withing the closure after inner, etc. That is the following won't compile: outer { value("1") }.
How can I implement something like this? In the end the data structures don't need to be immutable, it can be anything as long as it's strongly typed.
I have no familiarity with Scala macros, but can I solve this problem with macros by any chance?
The closest I have so far is the following implementation:
object DSL extends App {
def outer = new Outer()
class Outer(val values: mutable.MutableList[Inner] = mutable.MutableList.empty) {
def inner(id: String): Inner = {
val inner = new Inner(id)
values += inner
inner
}
def apply(func: Outer => Unit): Outer = {
func(this)
this
}
override def toString: String = s"Outer [${values.mkString(", ")}]"
}
class Inner(val id: String, val values: mutable.MutableList[Value] = mutable.MutableList.empty) {
def value(v: String): Value = {
val value = new Value(v)
values += value
value
}
def apply(func: Inner => Unit): Unit = func(this)
override def toString: String = s"Inner (${values.mkString(", ")})"
}
class Value(val str: String) {
override def toString: String = s"Value<$str>"
}
val value = outer { o =>
o.inner(id = "some_id") { i =>
i.value("value1")
i.value("value2")
}
}
println(value)
How can I get rid of the anonymous function annotations (i.e. o => and o., etc.)?
Alternatively is there a way to treat outer as new Outer (in this case the following code block will be treated as constructor and I will be able to call member functions)?
As you have noticed it boils down to
is there a way to treat outer as new Outer
and unfortunately the answer is no. I think this was possible in the experimental Scala-Virtualized fork. Personally, I think the new keyword is very annoying in Scala, too.
There are only two solutions I see.
use macros or a compiler plugin
use a global mutable builder object
I am aware of two projects that could do the job for you with the first approach:
dsl-paradise
sinject
I have tried with the former. I cloned the repository and changed scalaVersion in project/build.scala to "2.11.6" (instead of the snapshot). You can drop into the REPL using sbt sandbox/console.
The idea is to define functions that take a parameter marked #Implicit and that way you can "glue" the outer and inner parts of the DSL tree together:
import org.dslparadise.annotations._
import scala.collection.mutable.Builder
case class Outer(inner: Inner)
case class Inner(id: String, values: List[Value])
case class Value(value: String)
def outer(i: Inner) = Outer(i) // nothing special here
def inner(id: String)
(body: (Builder[Value, List[Value]] #Implicit) => Unit): Inner = {
val b = List.newBuilder[Value] // to "build" the contents of inner
body(b)
Inner(id, b.result)
}
def value(x: String)(implicit b: Builder[Value, List[Value]]): Value = {
val v = Value(x)
b += v // side-effect: populate the builder
v
}
Example:
scala> outer {
| inner(id = "asdf") {
| value("v1")
| value("v2")
| }
| }
res1: Outer = Outer(Inner(asdf,List(Value(v1), Value(v2))))
Voila!
The solution without plugin/macros would be to set-up for example ThreadLocal builders, but then you have no compile-time safety:
val values = new ThreadLocal[Builder[Value, List[Value]]]
def inner(id: String)(body: => Unit): Inner = {
val prev = values.get()
values.set(List.newBuilder[Value])
body
val v = values.get().result
values.set(prev)
Inner(id, v)
}
def value(x: String): Value = {
val v = Value(x)
values.get() += v
v
}
Example:
scala> inner(id = "asdf") { value("v1"); value("v2") }
res1: Inner = Inner(asdf,List(Value(v1), Value(v2)))
What I try to do is to come up with a case class which I can use in pattern matching which has exactly one field, e.g. an immutable set. Furthermore, I would like to make use of functions like map, foldLeft and so on which should be passed down to the set. I tried it as in the following:
case class foo(s:Set[String]) extends Iterable[String] {
override def iterator = s.iterator
}
Now if I try to make use of e.g. the map function, I get an type error:
var bar = foo(Set() + "test1" + "test2")
bar = bar.map(x => x)
found : Iterable[String]
required: foo
bar = bar.map(x => x)
^
The type error is perfectly fine (in my understanding). However, I wonder how one would implement a wrapper case class for a collection such that one can call map, foldLeft and so on and still receive an object of the case class. Would one need to override all these functions or is there some other way around?
Edit
I'm inclined to accept the solution of RĂ©gis Jean-Gilles which works for me. However, after Googling for hours I found another interesting Scala trait named SetProxy. I couldn't find any trivial examples so I'm not sure if this trait does what I want:
come up with a custom type, i.e. a different type than Set
the type must be a case class (we want to do pattern matching)
we need "delegate" methods map, foldLeft and so on which should pass the call to our actual set and return the resulting set wrapped arround in our new type
My first idea was to extend Set but my custom type Foo already extends another class. Therefore, the second idea was to mixin the trait Iterable and IterableLike. Now I red about the trait SetProxy which made me think about which is "the best" way to go. What are your thoughts and experiences?
Since I started learning Scala three days ago, any pointers are highly appreciated!
Hmm this sounds promissing to me but Scala says that variable b is of type Iterable[String] and not of type Foo, i.e. I do not see how IterableLike helps in this situation
You are right. Merely inheriting from IterableLike as shown by mpartel will make the return type of some methods more precise (such as filter, which will return Foo), but for others such as map of flatMap you will need to provide an appopriate CanBuildFrom implicit.
Here is a code snippet that does just that:
import collection.IterableLike
import collection.generic.CanBuildFrom
import collection.mutable.Builder
case class Foo( s:Set[String] ) extends Iterable[String] with IterableLike[String, Foo] {
override def iterator = s.iterator
override protected[this] def newBuilder: scala.collection.mutable.Builder[String, Foo] = new Foo.FooBuilder
def +(elem: String ): Foo = new Foo( s + elem )
}
object Foo {
val empty: Foo = Foo( Set.empty[String] )
def apply( elems: String* ) = new Foo( elems.toSet )
class FooBuilder extends Builder[String, Foo] {
protected var elems: Foo = empty
def +=(x: String): this.type = { elems = elems + x; this }
def clear() { elems = empty }
def result: Foo = elems
}
implicit def canBuildFrom[T]: CanBuildFrom[Foo, String, Foo] = new CanBuildFrom[Foo, String, Foo] {
def apply(from: Foo) = apply()
def apply() = new FooBuilder
}
}
And some test in the repl:
scala> var bar = Foo(Set() + "test1" + "test2")
bar: Foo = (test1, test2)
scala> bar = bar.map(x => x) // compiles just fine because map now returns Foo
bar: Foo = (test1, test2)
Inheriting IterableLike[String, Foo] gives you all those methods such that they return Foo. IterableLike requires you to implement newBuilder in addition to iterator.
import scala.collection.IterableLike
import scala.collection.mutable.{Builder, SetBuilder}
case class Foo(stuff: Set[String]) extends Iterable[String] with IterableLike[String, Foo] {
def iterator: Iterator[String] = stuff.iterator
protected[this] override def newBuilder: Builder[String, Foo] = {
new SetBuilder[String, Set[String]](Set.empty).mapResult(Foo(_))
}
}
// Test:
val a = Foo(Set("a", "b", "c"))
val b = a.map(_.toUpperCase)
println(b.toList.sorted.mkString(", ")) // Prints A, B, C
I find some confusing use of trait in some unittesting code, such as:
trait MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
And then instantiate the trait using new and meanwhile some expressions wrapped by curly braces followed the instantiation.
test("it is a test") {
new MyTrait {
// do something with t1 and t2
}
}
I am confused by this strange syntax.
My question is:
why use follow trait instantiation by curly braces?
what is the purpose of trait instantiation in this case and other cases might also be helpful?
You are not instantiating the traits: traits by themselves cannot be instantiated; only non-abstract classes can. What you are doing here is using Scala's shorthand for both defining an anonymous/nameless class that extends the trait and instantiating it in the same statement.
val anonClassMixingInTrait = new MyTrait {
def aFunctionInMyClass = "I'm a func in an anonymous class"
}
Is the equivalent of:
class MyClass extends MyTrait {
def aFunctionInMyClass = "I'm a func in a named class"
}
val namedClassMixingInTrait = new MyClass
The difference is you can only instaniate that anonymous class at the time of definition since it doesn't have a name and it can't have constructor arguments.
Steve Buzzard already explained, what anonymous classes are, but you also asked for the purpose. The purpose here is, that in tests you often have some default values, you want to use in every test. Sometimes you also have state, that may be changed by some of the tests. To always start with correct values (tests may also run in parallel) you can encapsulate them in these anonymous instances. The code inside this anonymous instance is the constructor, which will be evaluated at instantiation, thus executing your tests.
val t = new MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new AnyRef with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
is the same as
val t = new Object with MyTrait {
val t1 = ... //some expression
val t2 = ... //some expression
}
Example from "Hands on Scala" by Li HAOYI. Chapter 5.
trait StrParser[T]{ def parse(s: String): T }
object StrParser{
implicit object ParseInt extends StrParser[Int]{
def parse(s: String) = s.toInt
}
implicit object ParseBoolean extends StrParser[Boolean]{
def parse(s: String) = s.toBoolean
}
implicit object ParseDouble extends StrParser[Double]{
def parse(s: String) = s.toDouble
}
}
def parseFromString[T](s: String)(implicit parser: StrParser[T]) = {
parser.parse(s)
}
implicit def ParseSeq[T](implicit p: StrParser[T]) = new StrParser[Seq[T]]{
def parse(s: String) = s.split(',').toSeq.map(p.parse)
}
parseFromString[Seq[Int]]("1,2,3")
ParseSeq is Constructor for StrParser with Type Seq[T] and implicit parameter p:StrParser[T].
And one more StrParser Constructor for Type [T, V]
implicit def ParseTuple[T, V](implicit p1: StrParser[T], p2: StrParser[V]) =
new StrParser[(T, V)]{
def parse(s: String) = {
val Array(left, right) = s.split('=')
(p1.parse(left), p2.parse(right))
}
}
Now we can make
parseFromString[Seq[(Int, Boolean)]]("1=true,2=false,3=true,4=false")
Result is Seq[(Int, Boolean)] = ArraySeq((1,true), (2,false), (3,true), (4,false))
Having defined a class A which extends Ordering[A], and a subclass B of A, how do I automatically sort an Array of Bs? The Scala compiler complains that it "could not find implicit value for parameter ord: Ordering[B]". Here's a concrete REPL example (Scala 2.8), with A = Score and B = CommentedScore:
class Score(val value: Double) extends Ordered[Score] {
def compare(that: Score) = value.compare(that.value)
}
defined class Score
trait Comment { def comment: String }
defined trait Comment
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment
defined class CommentedScore
val s = new CommentedScore(10,"great")
s: CommentedScore = CommentedScore#842f23
val t = new CommentedScore(0,"mediocre")
t: CommentedScore = CommentedScore#dc2bbe
val commentedScores = Array(s,t)
commentedScores: Array[CommentedScore] = Array(CommentedScore#b3f01d, CommentedScore#4f3c89)
util.Sorting.quickSort(commentedScores)
error: could not find implicit value for parameter ord: Ordering[CommentedScore]
util.Sorting.quickSort(commentedScores)
^
How do I fix this (that is, sort an Array[B] = Array[CommentedScore] "for free", given that I know how to sort Array[A] = Array[Score]), in an elegant manner which avoids boilerplate?
Thanks!
Add the required implicit yourself:
implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)
You can put this in a CommentedScore companion object so that there is no boilerplate at use-site.
Edit: if you want the ordering method to be defined only at the top of the inheritance tree, you still have to provide an Ordering for each subclass, but you can define the compare method of the Ordering in terms of the one in the Score object. i.e.
object Score {
implicit val ord: Ordering[Score] = Ordering.by(_.value)
}
object CommentedScore {
implicit val csOrd = new Ordering[CommentedScore] {
def compare(x: CommentedScore, y: CommentedScore) = Score.ord.compare(x, y)
}
}
if you don't want to re-define this for each sub-class, you can use a generic method to produce the Ordering:
object Score {
implicit def ord[T <: Score]: Ordering[T] = Ordering.by(_.value)
}
This is a bit less efficient since being a def rather than a val, it creates a new Ordering each time one is required. However the overhead is probably tiny. Also note, the Ordered trait and compare method is not necessary now we have Orderings.
You might use Order from scalaz, which is contravariant, so you need not to define it for every subclass. Here is an example:
import scalaz._
import Scalaz._
class Score(val value: Double)
object Score {
implicit val scoreOrd: Order[Score] = orderBy(_.value)
}
trait Comment { def comment: String }
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment {
override def toString = s"cs($value, $comment)"
}
def quickSort[E: Order](list: List[E]): List[E] = list match {
case Nil => Nil
case head :: tail =>
val (less, more) = tail partition { e => implicitly[Order[E]].order(e, head) == LT }
quickSort(less) ::: head :: quickSort(more)
}
println(quickSort(List(
new CommentedScore(10,"great"),
new CommentedScore(5,"ok"),
new CommentedScore(8,"nice"),
new CommentedScore(0,"mediocre")
))) // List(cs(0.0, mediocre), cs(5.0, ok), cs(8.0, nice), cs(10.0, great))
This works:
val scoreArray: Array[Score] = Array(s, t)
util.Sorting.quickSort(scoreArray)
Or if you are starting from the Array[CommentedScore]:
val scoreArray: Array[Score] = commentedScores.map(identity)
util.Sorting.quickSort(scoreArray)
Note you can sort more simply with:
scoreArray.sorted
According to the docs, None object is intended to "represent non-existent values". As far as I've seen it's mostly used as an empty Option. But do you think it's a good idea to use it for other purposes. For example, in my library I want to have an universal "Empty" object which could be assigned for various missing values, where I would just implicitly convert the "Empty" value to my types as needed:
// In library:
trait A {
implicit def noneToT1(none: Option[Nothing]): T1 = defaultT1
implicit def noneToT2(none: Option[Nothing]): T2 = defaultT2
def f1: T1
def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
def f1 = None
def f2 = None
}
One reason for not (mis)using None in this fashion is that the user would expect that f1 and f2 return Option[T1] and Option[T2] respectively. And they don't. Off course, I could have def f1: Option[T1], but in this case the values are not actually optional, they just can have some default empty value, or a real value, I just want to create the default values "under the hood" and have some uniform way of saying "default" or "empty" through the entire library. So the question is, should I use None to express this "defaultness" or go for some custom type? Right now I'm using my own object Empty, but it feels a bit superfluous.
EDIT:
To ilustrate my question I'll add the code I am using right now:
// In library:
trait Empty
object Empty extends Empty
trait A {
implicit def emptyToT1(none: Empty): T1 = defaultT1
implicit def emptyToT2(none: Empty): T2 = defaultT2
def f1: T1
def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
def f1 = Empty
def f2 = Empty
}
class HalfFullA extends A {
def f1 = Empty
def f2 = someValue2
}
class FullA extends A {
def f1 = someValue1
def f2 = someValue2
}
My question is quite simple: is it a good idea to use scala's None instead of my Empty?
I would just use typeclasses for this:
trait WithDefault[T] {
def default: T
}
object WithDefault {
// if T1 is an existing class
implicit val t1Default = new WithDefault[T1] {def default = defaultT1}
}
//if T2 is your own class:
class T2 ...
object T2 {
implicit val withDefault = new WithDefault[T2] {def default = defaultT2}
}
then somewhere convenient:
def default[T : WithDefault] = implicitly[WithDefault[T]].default
and use:
class EmptyA {
def f1 = default[T1]
def f2 = default[T2]
}
Update: To accomudate Vilius, one can try this:
def default = new WithDefault[Nothing]{def default = error("no default")}
implicit def toDefault[U, T](dummy: WithDefault[U])(implicit withDefault: WithDefault[T]): T = withDefault.default
class EmptyA {
def f1: T1 = default
def f2: T2 = default
}
This has the benefit over the OP's original attempt in that each new class can define its own default (and others in WithDefault), rather than have everything in a trait A.
However, this doesn't work. See https://issues.scala-lang.org/browse/SI-2046
To work around this:
trait A {
def f1: T1
def f2: T2
implicit def toT1Default(dummy: WithDefault[Nothing]) = toDefault[T1](dummy)
implicit def toT2Default(dummy: WithDefault[Nothing]) = toDefault[T2](dummy)
}
class EmptyA extends A {
def f1 = default
def f2 = default
}
I think you should go for something much simpler. For instance, starting with your example and deleting extraneous stuff we very quickly get to,
trait A {
def noT1 = defaultT1
def noT2 = defaultT2
def f1: T1
def f2: T2
}
class EmptyA extends A {
def f1 = noT1
def f2 = noT2
}
I really don't see that the addition of Options or implicits to this would add any value, at least not unless there's some other unstated context for the question.
If you can't or don't want to define the default value using inheritance, I suggest to keep the new object. Reusing None for something else than the Some counterpart seems wrong and doesn't really save you much.