Triggered by another question (which has been subsequently edited away though), I wanted to try out how easy it would be to chain calls to Scala 2.10's Try construct (cf. this presentation), using for-comprehensions.
The idea is to have a list of tokens and match them against a sequence of patterns, then return the first error or the successfully matched pattern. I arrived at the following pretty awkward version, and I wonder if this can be made simpler and nicer:
import util.Try
trait Token
case class Ident (s: String) extends Token
case class Keyword(s: String) extends Token
case class Punct (s: String) extends Token
case object NoToken extends Token
case class FunctionDef(id: Ident)
case class Expect[A](expectation: String)(pattern: PartialFunction[Token, A]) {
def unapply(tup: (Try[_], Token)) = Some(tup._1.map { _ =>
pattern.lift(tup._2).getOrElse(throw new Exception(expectation))
})
}
Now construct the expectations for Keyword("void") :: Ident(id) :: Punct("(") :: Punct(")") :: tail
val hasVoid = Expect("function def starts with void") { case Keyword("void") => }
val hasIdent = Expect("expected name of the function") { case id: Ident => id }
val hasOpen = Expect("expected opening parenthesis" ) { case Punct("(") => }
val hasClosed = Expect("expected closing parenthesis" ) { case Punct(")") => }
Construct a full test case:
def test(tokens: List[Token]) = {
val iter = tokens.iterator
def next(p: Try[_]) = Some(p -> (if (iter.hasNext) iter.next else NoToken))
def first() = next(Try())
val sq = for {
hasVoid (vd) <- first()
hasIdent (id) <- next(vd)
hasOpen (op) <- next(id)
hasClosed(cl) <- next(op)
} yield cl.flatMap(_ => id).map(FunctionDef(_))
sq.head
}
The following verifies the test mehod:
// the following fail with successive errors
test(Nil)
test(Keyword("hallo") :: Nil)
test(Keyword("void" ) :: Nil)
test(Keyword("void" ) :: Ident("name") :: Nil)
test(Keyword("void" ) :: Ident("name") :: Punct("(") :: Nil)
// this completes
test(Keyword("void" ) :: Ident("name") :: Punct("(") :: Punct(")") :: Nil)
Now especially the additional flatMap and map in yield seems horrible, as well as the need to call head on the result of the for comprehension.
Any ideas? Is Try very badly suited for for comprehensions? Shouldn't either Either or Try be "fixed" to allow for this type of threading (e.g. allow Try as a direct result type of unapply)?
The trick seems to be to not create Try instances in the inner structure, but instead let that throw exceptions and construct one outer Try.
First, let's get rid of the Try[Unit]'s:
case class Expect(expectation: String)(pattern: PartialFunction[Token, Unit]) {
def unapply(token: Token) =
pattern.isDefinedAt(token) || (throw new Exception(expectation))
}
case class Extract[A](expectation: String)(pattern: PartialFunction[Token, A]) {
def unapply(token: Token) = Some(
pattern.lift(token).getOrElse(throw new Exception(expectation))
)
}
Then the checks become:
val hasVoid = Expect ("function def starts with void") { case Keyword("void") => }
val getIdent = Extract("expected name of the function") { case id: Ident => id }
val hasOpen = Expect ("expected opening parenthesis" ) { case Punct("(") => }
val hasClosed = Expect ("expected closing parenthesis" ) { case Punct(")") => }
And the test method:
def test(tokens: List[Token]) = Try {
val iter = tokens.iterator
def next() = Some(if (iter.hasNext) iter.next else NoToken)
(for {
hasVoid() <- next()
getIdent(id) <- next()
hasOpen() <- next()
hasClosed() <- next()
} yield FunctionDef(id)).head // can we get rid of the `head`?
}
Related
I'm trying to use Mockito to return some default values in tests but I get a 404 on it
My test:
#Test
fun `Should return 200, when sending a valid push notification`() {
// Arrange
Mockito.`when`(subscriptionStore.getSubscription{ it.peerID == validSubscription.peerID})
.thenReturn(
validSubscription
)
// Act
val response = mockMvc.post("/push") {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(validPushMessage)
}
// Assert
response.andDo { print() }
.andExpect {
status { isOk() }
}
}
and here's the method on the interface I try to mock:
interface SubscriptionStore {
fun addSubscription(newSubscription: Subscription)
fun getSubscriptions(): Collection<Subscription>
fun getSubscription(predicate: (Subscription) -> Boolean): Subscription?
fun deleteSubscription(peerID: String)
fun updateSubscription(subscription: Subscription)
class DuplicateElementException(msg: String) : Exception(msg)
}
and here's the usage of the mocked method that doesn't return what I told it but gives me 404:
override fun push(pushMessage: PushMessage) {
val recipientSubscription = subscribeService.getSubscription(pushMessage.recipient)
?: throw NoSuchElementException("Recipient not found")
}
which calls this from my subscriptionStore
override fun getSubscription(PeerID: String): Subscription? = subscriptionStore.getSubscription { it.peerID == PeerID}
In Kotlin, 2 different lambdas with identical code are not considered equal:
val fun1: (Int) -> Boolean = {it > 5}
val fun2: (Int) -> Boolean = {it > 5}
println(fun1 == fun2) // false
This is why your stubbing fails - you pass different lambda in your test, and a different one in the actual code
To answer the original post: I would probably relax stubbing requirements on the predicate and use the ArgumentMatchers.any argument matcher
On top of that - selection of item by ID is typically exposed by DBs as a separate operation, as it is the fastest way to reach the element. Maybe it is worth adding to your API as well?
I want to continue a suspend function in a dynamic proxy in the same coroutine.
Please have a look at the following code:
interface Adder {
suspend fun add(a: Int, b: Int): Int
}
val IH = InvocationHandler { _, method, args ->
val continuation = args.last() as Continuation<*>
val realArgs = args.take(args.size - 1)
println("${method.name}$realArgs")
GlobalScope.launch {
delay(5_000)
#Suppress("UNCHECKED_CAST") (continuation as Continuation<Int>).resume(3)
}
COROUTINE_SUSPENDED
}
fun main() {
val adder = Proxy.newProxyInstance(
Adder::class.java.classLoader, arrayOf(Adder::class.java), IH
) as Adder
runBlocking {
println(adder.add(1, 2))
}
}
It works fine. It runs the delay function in a new coroutine.
However, that's not what I want.
I want to run the InvocationHandler in the same coroutine as the one that was started with runBlocking.
Something like:
val IH = InvocationHandler { _, _, _ ->
delay(5_000)
3
}
This obviously won't compile because delay is a suspend function that must be run in a coroutine.
So the question is: How could I write the InvocationHandler for my intended behavior?
Any help would be very much appreciated.
I'd like to use this code in my RPC framework.
My real code would replace the delay call with non-blocking Ktor socket calls for serializing the data over the wire.
You can find the code example at: https://raw.githubusercontent.com/softappeal/yass/master/kotlin/yass/test/ch/softappeal/yass/remote/SuspendProxy.kt
I've found a solution for my problem:
package ch.softappeal.yass
import kotlinx.coroutines.*
import java.lang.reflect.*
import kotlin.coroutines.*
import kotlin.test.*
typealias SuspendInvoker = suspend (method: Method, arguments: List<Any?>) -> Any?
private interface SuspendFunction {
suspend fun invoke(): Any?
}
private val SuspendRemover = SuspendFunction::class.java.methods[0]
#Suppress("UNCHECKED_CAST")
fun <C : Any> proxy(contract: Class<C>, invoker: SuspendInvoker): C =
Proxy.newProxyInstance(contract.classLoader, arrayOf(contract)) { _, method, arguments ->
val continuation = arguments.last() as Continuation<*>
val argumentsWithoutContinuation = arguments.take(arguments.size - 1)
SuspendRemover.invoke(object : SuspendFunction {
override suspend fun invoke() = invoker(method, argumentsWithoutContinuation)
}, continuation)
} as C
interface Adder {
suspend fun add(a: Int, b: Int): Int
}
class SuspendProxyTest {
#Test
fun test() {
val adder = proxy(Adder::class.java) { method, arguments ->
println("${method.name}$arguments")
delay(100)
3
}
runBlocking { assertEquals(3, adder.add(1, 2)) }
}
}
Any comments?
Is this a good/problematic solution?
Could/should the "removing of suspend functionality" be added to the kotlin.coroutines library?
use runBlocking inside InvocationHandler:
val IH = InvocationHandler { _, _, _ ->
runBlocking{
delay(5_000)// now you can use suspend functions here
}
3
}
I currently cannot reproduce this in a minimum working example, but I'm working on it.
Adding a line in a dead code causes a crash at run-time.
Here are the relevant code snippets, first from the scala file:
// We are inside an object. Expr is a trait with many case classes.
case class Problem(in: Expr, out: Expr)
type RepairOutput = Either[String, Stream[Expr]]
private sealed trait RepairFinalTransform
...
private sealed trait TransformExtend extends RepairFinalTransform {
def continuation(repair: Problem => RepairOutput)
: Expr => RepairOutput
}
private case class TransformSolutionAndContinue(f: Expr => (Problem, Expr => Expr)) extends TransformExtend {
def continuation(repair: Problem => RepairOutput): Expr => RepairOutput = (x: Expr) => f(x) match {
case (p, rewriter) => repair(p) andMap rewriter
}
}
private case class TransformAndContinue(f: Expr => RepairOutput) extends TransformExtend {
def continuation(repair: Problem => RepairOutput): Expr => RepairOutput = f
}
The following code snippet
case c: TransformExtend =>
r = r andThen c.continuation(_repair)
, when working, is compiled as:
if ($is_Lexample_LambdaCalculus$TransformExtend(x1)) {
var x5 = $as_Lexample_LambdaCalculus$TransformExtend(x1);
var e$1 = r;
r = new $c_Lexample_LambdaCalculus$Retransformer().init___s_util_Either(e$1).andThen__F1__s_util_Either(x5.continuation__F1__F1(new $c_sjsr_AnonFunction1().init___sjs_js_Function1((function($this) {
return (function(original_problem$2) {
var original_problem = $as_Lexample_LambdaCalculus$Problem(original_problem$2);
return $m_Lexample_LambdaCalculus$().$$undrepair__Lexample_LambdaCalculus$Problem__s_util_Either(original_problem)
})
})(this))))
}
However, as soon as I add one occurrence of TransformAndContinue(???) (I did not have any before) in a place that is currently never executed, the above code becomes:
if ($is_Lexample_LambdaCalculus$TransformExtend(x1)) {
var x5 = $as_Lexample_LambdaCalculus$TransformExtend(x1);
var e$1 = r;
r = new $c_Lexample_LambdaCalculus$Retransformer().init___s_util_Either(e$1).andThen__F1__s_util_Either(x5.f$1)
}
Note that x5 is supposed to be a type cast to TransformExtend, which does not have the field f, only the continue method. Since f exists in both classes, its return type differs. Besides, the case class TransformSolutionAndContinue was used in many other places, so there is no reason why it calls f instead of continue.
So the translation to Javascript seems wrong (and actually, the errors fail on this point). I'm using scalajs 0.6.19 and compile using fastOptJS and scalatest.
Can you tell me what to change in my code so that the compilation is correct? Is it a known bug?
(first post)
usually im able to find answers here or elsewhere but no luck this time =(
Question: in Swift, how do you filter an array that is of a protocol type by an implementing type supplied as a function parameter?
protocol Aprotocol {
var number:Int { get set }
}
class Aclass: Aprotocol {
var number = 1
}
class AnotherClass: Aprotocol {
var number = 1
}
var array:[Aprotocol] = [ Aclass(), AnotherClass(), Aclass() ]
func foo (parameter:Aprotocol) -> Int {
return array.filter({ /* p in p.self == parameter.self */ }).count
}
var bar:Aprotocol = // Aclass() or AnotherClass()
var result:Int = foo(bar) // should return 2 or 1, depending on bar type
maybe this is not the right approach at all?
thanks!
Here is what I think you want:
return array.filter { (element: Aprotocol) -> Bool in
element.dynamicType == parameter.dynamicType
}.count
But I recommend this, which does the same, but without the useless instance of Aclass() which is passed in the answer on the top. Also this way is faster:
func foo <T: Aprotocol>(type: T.Type) -> Int {
return array.filter { (element: Aprotocol) -> Bool in
element.dynamicType == type
}.count
}
var result:Int = foo(Aclass)
The dynamicType will return the Type of an instance
Very easy:
return array.filter({ parameter.number == $0.number }).count
Kametrixoms solution works (if you use "is T" instead of "== type") but in my case, since i didnt know which implementing class was going to call it, had to go with this solution:
protocol Aprotocol: AnyObject {
var number:Int { get set }
}
class func foo(parameter: AnyObject) -> Int {
return array.filter ({ (element: Aprotocol) -> Bool in
object_getClassName(element) == object_getClassName(parameter)
}).count
}
I have the next code, and i would like to extract the default parametr from value.
//
def extractor[T] = macro extractorImpl[T]
def extractorImpl[T: c.WeakTypeTag](c: Context) = {
//first i got a type contructor
???
}
i try with attachments but attachments.all return a Set[Any] with (for example) SymbolSourceAttachment(val name: String = "new name")
SymbolSourceAttachment contain ValDef but i do not know how to extract from SymbolSourceAttachment ValDef.
By the way i should to get a Map[String, String]("name" -> "new name")
Example:
case class Person(name: String = "new name")
object Macro {
def extractor[T] = macro extractorImpl[T]
def extractorImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
c.weakTypeOf[T].declarations.collect {
case a: MethodSymbol if a.isConstructor =>
a.paramss.collect {
case b => b.collect {
case c =>
c.attachments.all {
case d => println(showRaw(d)) // => SymbolSourceAttachment(val name: String = "new name")
}
}
}
}
}
}
And macro should return Map("name" -> "new name")
Since you're seeing SymbolSourceAttachment, I assume you're using macro paradise (because it's an internal attachment used only in paradise), so I'll feel free to use quasiquotes :)
There's no easy way to get values of default parameters in Scala reflection API. Your best shot would be reverse-engineering the names of methods that are created to calculate default values and then referring to those.
SymbolSourceAttachment would sort of work if your macro is expanding in the same compilation run that compiles the case class, but it would break under separate compilation (attachments aren't saved in class files), and it wouldn't work in vanilla Scala (because this attachment is exclusive to paradise).
=== Macros.scala ===
import scala.reflect.macros.Context
import scala.language.experimental.macros
object Macros {
def impl[T](c: Context)(T: c.WeakTypeTag[T]): c.Expr[Map[String, Any]] = {
import c.universe._
val classSym = T.tpe.typeSymbol
val moduleSym = classSym.companionSymbol
val apply = moduleSym.typeSignature.declaration(newTermName("apply")).asMethod
// can handle only default parameters from the first parameter list
// because subsequent parameter lists might depend on previous parameters
val kvps = apply.paramss.head.map(_.asTerm).zipWithIndex.flatMap{ case (p, i) =>
if (!p.isParamWithDefault) None
else {
val getterName = newTermName("apply$default$" + (i + 1))
Some(q"${p.name.toString} -> $moduleSym.$getterName")
}
}
c.Expr[Map[String, Any]](q"Map[String, Any](..$kvps)")
}
def extractor[T]: Map[String, Any] = macro impl[T]
}
=== Test.scala ===
case class C(x: Int = 2, y: String, z: Boolean = true)(t: String = "hello")
object Test extends App {
println(Macros.extractor[C])
}
17:10 ~/Projects/Paradise2103/sandbox/src/main/scala (2.10.3)$ scalac Macros.scala && scalac Test.scala && scala Test
Map(x -> 2, z -> true)