Looking at the following Scala in Depth code, what does handle -> callback mean?
trait Observable {
type Handle
def observe(callback: this.type => Unit): Handle = {
val handle = createHandle(callback)
callbacks += (handle -> callback)
handle
[code omitted]
}
-> ultimately comes from scala.ArrowAssoc. scala.Predef also defines:
#inline implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
which causes an implicit conversion of Any to an ArrowAssoc. This has the effect of adding ArrowAssoc's -> method to all objects (because all objects inherit from Any).
As to what -> does, it merely returns a Tuple2 of the two parameters. Or to put it another way, (handle -> callback) is more or less identical to (handle, callback).
Although you've deleted the definition, callbacks is probably a mutable.Map object. += adds (or updates) an entry in said map associating handle to callback. So basically, this appears to be adding the newly-created handle and the callback to a map of callbacks.
Handle is an "abstract type". It must be defined in a concrete subclass.
callback is a function that takes a (this.type) and returns nothing (Unit).
The -> syntax is just alternate syntax for a tuple:
(3 -> "abcd") is the same as (3, "abcd")
Related
I would like to have:
def myMethod[T < ???](f: T): Unit = {
f()
}
The rest of the method is not really important but is it possible to replace ??? by somethind which would make sure T is a method
and if possible to go even further and make sure the return type of T is something defined ?
Like [T < (_*) => Int]
Thank you.
Would defining a type, like in the following trivial example, address your need?
type Fcn = String => Int
def myMethod(s: String, f: Fcn): Unit = {
println(f(s))
}
myMethod("hello", (s: String) => s.length)
// 5
You can use function literals:
def myMethod[A, T](f: A => T) {
f(someAValue)
}
or if you want functions that take no arguments:
def myMethod[T](f: () => T) {
f()
}
But judging by your comments, it seems like you specifically want to reference methods, and query the method for information about itself, which is not a feature of basic Scala. You may be able to do some of that with reflection, but reflection is an area best avoided.
Technically, you can't directly pass a method, since a method is not a value that you can instantiate and pass-around. What is usually passed around is a function instance. And when it appears that you're passing a method, the compiler is actually creating a function instance for you (method lifting or eta-expansion).
But that is not going to work if you're looking to inspect meta data about that method (name, deprecation). For that, you're probably looking for reflection. You can have your method take an instance of java.reflect.Method but that will require that you obtain that at call-site.
I'm not sure what this pattern is called, but could this be written in scala and if so how would I go about doing this?
val userId = 1
def getUser(userId: Int): User = {
CacheLookup.getOrElse(userId) {
userDao.get(userId)
}
}
I guess this would be an anonymous function as a parameter?
There's something similar to that on maps -- check mutable map's withDefault. The difference is that it doesn't update the map, which seems to be what you want (and, in fact, what many people using withDefault wants, by the questions we get here).
An alternative is memoization. You'd have to find that outside the standard library, but it works a bit like that except you don't do the cache thing explicitly. Basically, you write a function userId => userDao.get(userId), and then you get a memoized version of it. When you call the memoized version, it will check whether there's a cached version for the parameter and serve that if so.
Note that there are important issues with the cache. Do you want/can have it increase indefinitely, or should it be limited? Will the keys expire after a time? This sort of control is important, and whatever solution you pick must support it.
As for how to implement it, it could go like this:
def memoize[A, B](f: A => B): A => B = {
var map = Map.empty[A, B]
(key: A) => {
if (!map.contains(key)) map += key -> f(key)
map(key)
}
}
val getUser = memoize((userId: Int) => userDao.get(userId))
This memoization function takes a Function1 (that is, a function with one parameter) and takes a Function1 that does caching (in a very basic sense, without any of the controls I mentioned). For functions taking more parameters you'd have to create different versions of this, or make them tupled.
Then we get to the use, where I pass the function that takes an userId (an Int) and returns a User, and we get the same function back, but now doing caching.
Here's an example of tupling, just out of curiosity:
scala> val mult = memoize(((x: Int, y: Int) => x * y).tupled)
mult: ((Int, Int)) => Int = <function1>
scala> mult(2, 3)
res18: Int = 6
scala> mult(2 -> 3)
res19: Int = 6
The first call, mult(2, 3) is actually a Scala oddity. When calling functions that take a tuple, if you are passing multiple parameters then Scala will auto-tuple then.
It's not entirely clear what you're asking. If you're wondering how to implement the getOrElse method so that the database call would only be conditionally evaluated, the answer is to just use an ordinary higher-order function:
def getOrElse(userId: Int)(getter: Int => User) =
if (cache contains userId)
cache get userId
else
getter(userId)
I was tired of always doing something like the following in order to do database access using slick for each of my domain entities.
database withSession {
implicit session =>
val entities = TableQuery[EntityTable]
val id = //Some ID
val q = for {
e <- entities if e.id === id
} yield (e)
val entity = q.first
}
(Note: EntityTable was defined like described here)
So I decided that I want a generic database access object that handles this for me. The usage should look something like
[...]
val entityDAO = new GenericDAO[Entity, EntityTable, String]()
[...]
database withSession { implicit session =>
val id = // Some ID
val entity = entityDAO.get(id)
}
My try of the implementation of the GenericDAO looks like this
class GenericDAO[T, TB, PK](implicit session: Session) {
val entities = TableQuery[TB] // Line 1
def get(id: PK): T = {
val q = for {
e <- entities
} yield (e)
val res: T = q.first
res
}
}
But line 1 leaves me with a compiler error stating that something is wrong with the TB argument.
Multiple markers at this line
- type arguments [TB] conform to the bounds of none of the overloaded alternatives of value apply: [E <:
scala.slick.lifted.AbstractTable[]]=>
scala.slick.lifted.TableQuery[E,E#TableElementType] [E <:
scala.slick.lifted.AbstractTable[]](cons: scala.slick.lifted.Tag =>
E)scala.slick.lifted.TableQuery[E,E#TableElementType]
- wrong number of type parameters for overloaded method value apply with alternatives: [E <: scala.slick.lifted.AbstractTable[]]=>
scala.slick.lifted.TableQuery[E,E#TableElementType] [E <:
scala.slick.lifted.AbstractTable[]](cons: scala.slick.lifted.Tag =>
E)scala.slick.lifted.TableQuery[E,E#TableElementType]
Any suggesions on this issue? Or maybe I am wrong and it is supposed to be implemented in another way. I am open for any solution. Thanks!
First of all, you could write
val entities = TableQuery[EntityTable] // put in a central place for re-use
and then
database.withSession(
(for {
e <- entities if e.id === /*Some ID*/
} yield e).first()(_)
)
or this
database.withSession(entities.filter(_.id === /*Some ID*/).first()(_))
or this
val get = entities.findBy(_.id) // <- reuse this
database.withSession(get(/*Some ID*/).first()(_))
for brevity. This probably makes your whole DAO unnecessary (which is great :)!).
Regarding the error message you got. TableQuery[TB]is a macro, which is a short-hand for TableQuery(tag => new TB(tag)), TB must be a Table and support object creation. You cannot just use the TableQuery macro on an unconstrained type parameter your got from a DAO wrapper. You could constraint TB <: Table[_] but it still wouldn't support object creation, which you cannot constraint in Scala. You could only provide a factory to your DAO (a common pattern is to fetch one as an implicit argument), but that all does not make sense, when you can just write your TableQuery once and store it in a globally accessible place.
Update:
The shortcut works for all of these methods the same way. It's plain Scala. You just turn the method into a function and pass it to the higher-order function withSession, which requires a function from session to anything. Just be aware, that some Slick methods have an empty argument list, which requires ()(_) to turn them into a function and some only have the implicit argument list, which requires only (_). E.g. database.withSession(entities.filter(_.id === /*Some ID*/).delete(_)).
If you wonder about the _. Scala distinguishes methods from functions. def foo(a: A, b: B, ...): R is a method but can be turned into a function of type (A,B,C) => R using foo _. This conversion is called eta expansion and googling for it will turn up more info. Sometimes when a function expected, but you provide a method, the Scala compiler infers the _ and you don't have to write it explicitly. You can also provide some parameters and use _ in place of the parameters you don't want to apply yet. In that case you partially apply the method and get a function back. This is what we do here. We use _ in the place where the methods usually expect a session and get a function back that takes a session. When exactly you have to use _ or (_) or ()(_) has to do with the method signatures and the details interplay between implicit argument lists, nullary methods, methods with empty argument lists, which is general Scala knowledge worth researching at some point.
This was a huge help to me. A complete working generic dao https://gist.github.com/lshoo/9785645
I have a loan pattern that applies a function n times where 'i' is the incrementing variable. "Occasionally", I want the function passed in to have access to 'i'....but I don't want to require all functions passed in to require defining a param to accept 'i'. Example below...
def withLoaner = (n:Int) => (op:(Int) => String) => {
val result = for(i <- 1 to n) yield op(i)
result.mkString("\n")
}
def bob = (x:Int) => "bob" // don't need access to i. is there a way use () => "bob" instead?
def nums = (x:Int) => x.toString // needs access to i, define i as an input param
println(withLoaner(3)(bob))
println(withLoaner(3)(nums))
def withLoaner(n: Int) = new {
def apply(op: Int => String) : String = (1 to n).map(op).mkString("\n")
def apply(op: () => String) : String = apply{i: Int => op()}
}
(not sure how it is related to the loan pattern)
Edit Little explanation as requested in comment.
Not sure what you know and don't know of scala and what you don't undestand in that code. so sorry if what I just belabor the obvious.
First, a scala program consist of traits/classes (also singleton object) and methods. Everything that is done is done by methods (leaving constructor aside). Functions (as opposed to methods) are instances of (subtypes of) the various FunctionN traits (N the number of arguments). Each of them has as apply method that is the actual implemention.
If you write
val inc = {i: Int => i + 1}
it is desugared to
val inc = new Function1[Int, Int] {def apply(i: Int) = i + 1}
(defines an anonymous class extending Function1, with given apply method and creating an instance)
So writing a function has rather more weight than a simple method. Also you cannot have overloading (several methods with the same name, differing by the signature, just what I did above), nor use named arguments, or default value for arguments.
On the other hand, functions are first classes values (they can be passed as arguments, returned as result) while methods are not. They are automatically converted to functions when needed, however there may be some edges cases when doing that. If a method is intended solely to be used as a function value, rather than called as a method, it might be better to write a function.
A function f, with its apply method, is called with f(x) rather than f.apply(x) (which works too), because scala desugars function call notation on a value (value followed by parentheses and 0 or more args) to a call to method apply. f(x) is syntactic sugar for f.apply(x). This works whatever the type of f, it does not need to be one of the FunctionN.
What is done in withLoaner is returning an object (of an anonymous type, but one could have defined a class separately and returned an instance of it). The object has two apply methods, one accepting an Int => String, the other one an () => String. When you do withLoaner(n)(f) it means withLoaner(n).apply(f). The appropriate apply method is selected, if f has the proper type for one of them, otherwise, compile error.
Just in case you wonder withLoaner(n) does not mean withLoaner.apply(n) (or it would never stop, that could just as well mean withLoaner.apply.apply(n)), as withLoaner is a method, not a value.
Can anyone explain the compile error below? Interestingly, if I change the return type of the get() method to String, the code compiles just fine. Note that the thenReturn method has two overloads: a unary method and a varargs method that takes at least one argument. It seems to me that if the invocation is ambiguous here, then it would always be ambiguous.
More importantly, is there any way to resolve the ambiguity?
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
trait Thing {
def get(): java.lang.Object
}
new MockitoSugar {
val t = mock[Thing]
when(t.get()).thenReturn("a")
}
error: ambiguous reference to overloaded definition,
both method thenReturn in trait OngoingStubbing of type
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
and method thenReturn in trait OngoingStubbing of type
(java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
match argument types (java.lang.String)
when(t.get()).thenReturn("a")
Well, it is ambiguous. I suppose Java semantics allow for it, and it might merit a ticket asking for Java semantics to be applied in Scala.
The source of the ambiguitity is this: a vararg parameter may receive any number of arguments, including 0. So, when you write thenReturn("a"), do you mean to call the thenReturn which receives a single argument, or do you mean to call the thenReturn that receives one object plus a vararg, passing 0 arguments to the vararg?
Now, what this kind of thing happens, Scala tries to find which method is "more specific". Anyone interested in the details should look up that in Scala's specification, but here is the explanation of what happens in this particular case:
object t {
def f(x: AnyRef) = 1 // A
def f(x: AnyRef, xs: AnyRef*) = 2 // B
}
if you call f("foo"), both A and B
are applicable. Which one is more
specific?
it is possible to call B with parameters of type (AnyRef), so A is
as specific as B.
it is possible to call A with parameters of type (AnyRef,
Seq[AnyRef]) thanks to tuple
conversion, Tuple2[AnyRef,
Seq[AnyRef]] conforms to AnyRef. So
B is as specific as A. Since both are
as specific as the other, the
reference to f is ambiguous.
As to the "tuple conversion" thing, it is one of the most obscure syntactic sugars of Scala. If you make a call f(a, b), where a and b have types A and B, and there is no f accepting (A, B) but there is an f which accepts (Tuple2(A, B)), then the parameters (a, b) will be converted into a tuple.
For example:
scala> def f(t: Tuple2[Int, Int]) = t._1 + t._2
f: (t: (Int, Int))Int
scala> f(1,2)
res0: Int = 3
Now, there is no tuple conversion going on when thenReturn("a") is called. That is not the problem. The problem is that, given that tuple conversion is possible, neither version of thenReturn is more specific, because any parameter passed to one could be passed to the other as well.
In the specific case of Mockito, it's possible to use the alternate API methods designed for use with void methods:
doReturn("a").when(t).get()
Clunky, but it'll have to do, as Martin et al don't seem likely to compromise Scala in order to support Java's varargs.
Well, I figured out how to resolve the ambiguity (seems kind of obvious in retrospect):
when(t.get()).thenReturn("a", Array[Object](): _*)
As Andreas noted, if the ambiguous method requires a null reference rather than an empty array, you can use something like
v.overloadedMethod(arg0, null.asInstanceOf[Array[Object]]: _*)
to resolve the ambiguity.
If you look at the standard library APIs you'll see this issue handled like this:
def meth(t1: Thing): OtherThing = { ... }
def meth(t1: Thing, t2: Thing, ts: Thing*): OtherThing = { ... }
By doing this, no call (with at least one Thing parameter) is ambiguous without extra fluff like Array[Thing](): _*.
I had a similar problem using Oval (oval.sf.net) trying to call it's validate()-method.
Oval defines 2 validate() methods:
public List<ConstraintViolation> validate(final Object validatedObject)
public List<ConstraintViolation> validate(final Object validatedObject, final String... profiles)
Trying this from Scala:
validator.validate(value)
produces the following compiler-error:
both method validate in class Validator of type (x$1: Any,x$2: <repeated...>[java.lang.String])java.util.List[net.sf.oval.ConstraintViolation]
and method validate in class Validator of type (x$1: Any)java.util.List[net.sf.oval.ConstraintViolation]
match argument types (T)
var violations = validator.validate(entity);
Oval needs the varargs-parameter to be null, not an empty-array, so I finally got it to work with this:
validator.validate(value, null.asInstanceOf[Array[String]]: _*)