I'm working on an event library in Scala. In my library you can define events like this:
val e1 = new ImperativeEvent[Int]
You can trigger them like this:
e1(42)
You can create reactions like this:
val r1 = (i: Int) => println(i)
And attach them to the event like this:
e1 += r1
There is also some other stuff (like event transformations, compositions etc). I use the Esper CEP engine as the backend of my library. Esper uses an SQL-like language called EPL for most operations.
I'm trying to implement some more advanced concepts like event joins. So now you can define events with multiple properties like this (using tuple types):
val e2 = new ImperativeEvent[(Int, String)]
And then join them like this:
val e3 = e1 join e2 windowLength (30) on "E1.P1 = E2.P1"
which performs a join of e1 and e2 on the last 30 occurrances of both on the condition that their respective first properties are equal.
This is alright but I'd like to get rid of the strings in my implementation to make the event expressions type checkable. I'd like to change the join expression to something like this:
val e3 = e1 join e2 windowLength (30) on e1._1 === e2._1
similar to the way it is done in eg. Squeryl. The problem with this is, I can't access the types of the elements of the tuple type...
How can I access the tuple types statically? Right now I've only managed to access them at run-time through reflection which does not help me. I'm pretty sure that what I want to achieve is not possible with tuples but I'm wondering if using HLists from the shapeless library or something similar might help in achieving my goal.
It means an abstract type member is defined (inside some context, e.g. a trait or class), so that concrete implementations of that context must define that type.
A classOf[T] is a value of type Class[T] . In other words, classOf[T]: Class[T] . For example: scala> val strClass = classOf[String] strClass: Class[String] = class java. lang. String scala> :t strClass Class[String]
For example, a type constructor does not directly specify a type of values. However, when a type constructor is applied to the correct type arguments, it yields a first-order type, which may be a value type. Non-value types are expressed indirectly in Scala.
Language. Methods in Scala can be parameterized by type as well as by value. The syntax is similar to that of generic classes.
Without more details on your DSL, I'm afraid it's not clear what you mean by "access the tuple types statically". Here's a simplified version of the API that has no trouble with tuple types:
class Event[T] {
def joinOn[T2, R](ev2: Event[T2])(f: (T, T2) => R) = new Event[R]
}
You can use this as follows:
val e1 = new Event[(Int, String)]
val e2 = new Event[(Int, String)]
val e3 = e1.joinOn(e2)(_._1 == _._2)
It should be easy to see how this could be extended to supporting your join/windowLength/on syntax.
Update:
I can see that your use case is complicated by the fact that you need to translate the Scala-encoded query expression to another query language. In this case, you want the on
method's signature to look like:
def on[T2, R](f: (Expr[T], Expr[T2]) => Expr[R]): Event[R]
Internally, each event object would create its own Expr representation and would pass this representation into the function supplied to the on
method.
The Expr
type could be defined like:
trait Expr[T] {
protected val repr: String
def _1[A](implicit ev: T <:< Tuple2[A,_]): Expr[A] =
??? // create an Expr[A] whose string representation is (repr + ".P1")
// abstracting over tuple arities (using Shapeless)
import shapeless._, nat._
@scala.annotation.implicitNotFound("A tuple with at least 3 elements is required")
type At2 = ops.tuple.At[T, _2]
def _3(implicit at: At2): Expr[at.Out] =
??? // create an Expr[at.Out] whose string representation is (repr + ".P3")
def ===(other: Expr[T]): Expr[Boolean] =
??? // create an Expr[T] whose string representation is (repr + " = " + other.repr)
}
This is obviously dramatically simplified but should help to get you started.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With