'with' structure type and exception handling - ponylang

The following code does not compile because the compiler believes that the type of the 'with' expression is (U8 | None) although as I don't see how it may happen that it's body will get to None
class Disposable
new create() => None
fun dispose() => None
fun value(): U8 => 42
primitive TestWith
fun apply(): U8 =>
with d = Disposable do
d.value()
end
But if I add the 'else' section to the 'with' - everything gets fine with types. But the compiler complains that "try expression never results in an error"
primitive TestWith
fun apply(): U8 =>
with d = Disposable do
d.value()
else
0
end
Any ideas?

with block makes sure the object is disposed even when nested code reports error. In your case the body d.value() does not produce error. You don't need with statement in this case.
You have two options to make your code compile:
a) call dispose() directly (doesn't look elegant at all):
class Disposable
new create() => None
fun dispose() => None
fun value(): U8 => 42
primitive TestWith
fun apply(): U8 =>
let d = Disposable
let result = d.value()
d.dispose() // dispose manually
result
b) have a partial function inside with body:
class Disposable
new create() => None
fun dispose() => None
fun value(): U8? => error // partial function
primitive TestWith
fun apply(): U8 =>
with d = Disposable do
d.value() // possible failure here
end

Related

Type system not allowing subtype as a type constructor

I'm trying to build the following type structure for a library I'm writing, and I'm having trouble with the type system.
CarLike
trait CarLike[T, C <: CarLike[T,C]] {
val parts: Seq[T]
def crash(other: C, speed: Int): C
//... other methods
}
SimpleCar
class SimpleCar[T](val parts: Seq[T]) extends CarLike[T, SimpleCar[T]] {
def crash(other: SimpleCar[T], speed: Int) = {
//Some logic to crash with the other car
val newParts = damage(parts) //parts have changed
new SimpleCar(newParts)
}
//...other methods
}
SportsCar
class SportsCar(val sParts: Seq[String]) extends SimpleCar[String](sParts){
override def crash(other: SimpleCar[String], speed: Int): SimpleCar[String] = {
//Some other logic for crashing a sport car
val newParts = damage(parts) //parts have changed
new SportsCar(newParts)
}
//...other methods
}
Crasher
case class Crasher[T, C <: CarLike[T,C]](
partsDamager: T => T,
carChecker: C => Seq[T]
/*... more parameters*/
){
def test(cycles:Int) = {
//Some logic to run a crash of two cars
}
}
Code
//...
val crasher = Crasher[String, SportsCar](
(s: String) => s.tail,
(c: SportsCar) => c.parts.filter(p => p.length > 0)
/*Many arguments*/
)
crasher.test(20)
//...
The idea is to allow the user of the library to be able to choose between using the default SimpleCar and implementing his own implementation of CarLike.
Also, users can choose the type for the car's parts. In this simple example the parts are String, but can easily be a custom class, which can be leveraged in the crash method of a custom class.
When compiling, I get the following compilation error:
type arguments [String,my.package.SportsCar] do not conform to method apply's type parameter bounds [T,C <: crashing.CarLike[T,C]]
val crasher = Crasher[String, SportsCar](
Clearly there's something I'm missing here. Why doesn't the compiler agree that SportsCar is a legal subtype of CarLike?
A SportsCar is not a CarLike[String, SportsCar], it is a CarLike[String, SimpleCar[String]]. Note that SportsCar extends SimpleCar[String], but that doesn't help, as CarLike is not covariant in C.
You can't really make CarLike covariant in C, as its crash method accepts a C. Instead, you can pass SimpleCar[String] to Crasher (after all, sports cars can crash with other cars, right?):
val crasher = Crasher[String, SimpleCar[String]](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)
Or, you can modify Crasher to take another type parameter:
case class Crasher[T, C <: CarLike[T, C], X <: C](partsDamager: T => T,
carChecker: X => Seq[T]) {
// ...
}
val crasher = Crasher[String, SimpleCar[String], SportsCar](
s => s.tail,
c => c.parts.filter(p => p.length > 0)
)

Scala: why is a type used as a method call?

Scala: why is a type used as a method call?
I'm new to Scala and I'm reading "Functional Programming in Scala"
by PAUL CHIUSANO and RÚNAR BJARNASON.
I'm trying to understand the source code of parser combinator in Chapter 9, but I'm stuck by a
problem: in the source code, Parser[A] is declared as a type, but I can see that instances of
Parser[A] is used as a method call.
My question is: why instance of a type can be used as a method
call?
def or[A](p: Parser[A], p2: => Parser[A]): Parser[A] =
s => p(s) match { // ========> p is used as a method call.
case Failure(e,false) => p2(s)
case r => r // committed failure or success skips running `p2`
}
Link to the source code:
https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/parsing
Code snippet:
trait Parsers[Parser[+_]] { self =>
.....
}
object ReferenceTypes {
/** A parser is a kind of state action that can fail. */
type Parser[+A] = ParseState => Result[A]
case class ParseState(loc: Location) {
......
}
sealed trait Result[+A] {
......
}
case class Success[+A](get: A, length: Int) extends Result[A]
case class Failure(get: ParseError, isCommitted: Boolean) extends Result[Nothing]
}
object Reference extends Parsers[Parser] {
......
def or[A](p: Parser[A], p2: => Parser[A]): Parser[A] =
s => p(s) match {
case Failure(e,false) => p2(s)
case r => r // committed failure or success skips running `p2`
}
.....
}
In the code you quoted, Parser[+A] is explicitly declared as function type
type Parser[+A] = ParseState => Result[A]
Therefore, values of type Parser[+A] can be applied to values of type ParseState. The usual syntax for applying a function p of type X => Y to a value s of type X is
p(s)
So, it's just usual function application, it's not even some fancy overriden apply method of some user-defined class.
A method call usually looks as follows:
obj.methodName(argument)
it requires an object on which the method is called. This can be omitted if the object is this, or if you have previously imported
import obj._
so that all methods of this object are available in the current scope. In all other cases, you need a receiving object on which you invoke a method.
The function application
p(s)
actually desugars into a special method call
p.apply(s)
but that's an aside, it's not really relevant for the question.

Scala generics: why two types with the same upper bound are not compatible?

I am confused with how bounds work in Scala generics. Consider the following:
sealed trait MessageBody
case class Body1() extends MessageBody
case class Body2() extends MessageBody
sealed trait MessageKey[T <: MessageBody]
case object Key1 extends MessageKey[Body1]
case object Key2 extends MessageKey[Body2]
type MessageHandler[B <: MessageBody] = PartialFunction[MessageKey[B], B => Unit]
abstract class Handler {
def messageHandler[B <: MessageBody]: MessageHandler[B]
}
class ProcessingHandler[ReturnType <: MessageBody](val onSuccess: MessageKey[ReturnType]) extends Handler {
override def messageHandler[B <: MessageBody]: MessageHandler[B] = {
case `onSuccess` => success
}
def success(msg: ReturnType): Unit = println(msg)
}
This gives me an error:
error: type mismatch;
found : ReturnType => Unit
required: B => Unit
case `onSuccess` => success
^
In my naive understanding, both ReturnType and B are subtypes of MessageBody and thus must be compatible. So why are they not compatible, and how should I write my code to make them compatible?
EDIT: The following piece of code works just fine, and if I mix the relation between the MessageKey and MessageBody instances anywhere, I get a nice compile time error.
class ProcessingHandler2 extends Handler {
override def messageHandler[B <: MessageBody]: MessageHandler[B] = {
case Key1 => h1
// case Key1 => h2 // gives compile-time error
case Key2 => h2
}
def h1(x: Body1): Unit = println(x)
def h2(x: Body2): Unit = println(x)
}
val handler: Handler = new ProcessingHandler2
handler.messageHandler(Key1)(Body1())
// handler.messageHandler(Key1)(Body2()) // gives compile-time error
EDIT: Obviously, there is no way to compile check this: handler.messageHandler(Key3) and this will result in a MatchError at run-time.
Let's say you have an object of type ProcessingHandler[Body1] and then call messageHandler[Body2] on it. According to the signature, it should return a Body2 => Unit, but you try to return a Body1 => Unit. If you were trying to return a MessageBody => Unit, that would be fine as MessageBody is a superclass of Body2, but Body1 is not. They're both children of the same superclass, but that doesn't make them compatible, that is you can't pass a Body2 as an argument to a function that takes a Body1 or vice versa.
Depending on what exactly your requirements are, there are multiple things you could do:
You could make Handler generic instead of messageHandler and then extend Handler[ReturnType] (or you could give Handler a member type and use it in messageHandler).
Or you could make success take a MessageBody as its argument instead of a ReturnType.

Cast functions in scala

I have the base class Message and two derived classes One and Two. Method regHandler accepts function Message => Message as argument. When i created method handler and passed it to regHandler, it throws cast error.
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(one: One) : Two = {
new Two
}
regHandler(handler) // <- error here
I tried change my code like this:
var f : Handler
def regHandler[T >: Message, R >: Message](handler: T => R) = {
f = handler // <- but cast error here occurred
}
How do i need change my code to make it work ?
There is a very good reason it doesn't work: your Handler definition says it accepts any Message, but handler only accepts One. Kolberg proposes one solution, but the simpler one would be just to fix handler:
def handler(m: Message) = m match {
case one: One => new Two
case _ => // whatever you want to do here
}
You can throw an exception, which would be equivalent to other answers, except you can have a better error message; you can remove the line, which will throw MatchError; you can return Option[Message]; etc.
Now you can assign it, store it in a map, etc. easily:
object Main extends App {
class Message
class One extends Message
class Two extends Message
type Handler = Message => Message
def regHandler(handler: Handler) {}
def handler(m: Message) = m match {
case one: One => new Two
case _ => throw new Exception(s"handler expected One, got $m")
}
regHandler(handler)
val f: Handler = handler // no _ required
val map: Map[String, Handler] = Map("1" -> handler)
}
Or if you really don't want to change method signatures, make Handlers out of them explicitly (it could be an implicit conversion as well, but since it can introduce errors, I don't recommend it):
object Handler {
def apply[A <: Message, B <: Message](f: A => B): Handler = f.asInstanceOf[Handler]
// alternately if you want to handle ClassCastException for wrong argument type
// def apply[A <: Message, B <: Message](f: A => B): Handler =
// x => try { f(x) } catch { case e: ClassCastException => ... }
}
regHandler(Handler(handler))
The type bounds in
def regHandler[T >: Message, R >: Message](handler: T => R) = {
are wrong, because with >: you are telling the compiler that T,R should be super types of Message. I think you want sub types of Message:
def regHandler[T <: Message, T <: Message](handler: T => R) {}
def handler(one: One) : Two = {
new Two
}
regHandler(handler)
works for me.
EDIT:
OK, my answer was incomplete. Here is a complete and working example:
class Message
class One extends Message
class Two extends Message
type Handler[A <: Message, B <: Message] = A => B
def regHandler[A <: Message, B <: Message](a: A)(handler: Handler[A, B]): Unit = {
println(s"${handler(a)}")
}
def handler(one: One) : Two = {
new Two
}
regHandler(new One)(handler)
EDIT 2:
For usage in a map function or to assign to a var/val in this specific scenario add _:
val f: Handler[_, _] = handler _
val map = Map(new One -> handler _)
val test = map.map {case (one, h) => h(one)}
You can use variance annotation with wildcard types. Check this:
object Main {
class Message
class One extends Message
class Two extends Message
class Three extends Message
class Four extends Message
type HandlerType[+A <: Message, +B <: Message] = A => B
var f: HandlerType[_, _] = _
def regHandler(handler: HandlerType[_, _]) = {
f = handler // <- but cast error here occurred
}
def main(args: Array[String]) {
def handler12(x: One): Two = new Two
def handler23(x: Two): Three = new Three
def handler34(x: Three): Four = new Four
val h12 = handler12(_)
val h23 = handler23(_)
val h34 = handler34(_)
val handlersMap: Map[String, HandlerType[_, _]] = Map(
"12" -> h12,
"23" -> h23,
"34" -> h34)
handlersMap foreach {
case (k, h) =>
println(k)
println(h)
val hd: HandlerType[Message, Message] = h
val m: Message = new One
println(hd(m))
}
regHandler(h12)
}
}
Although you can store the handlers into a map, it creates additional types which introduce more complexity. I think there should be a better way to handle this problem.

How is this a type mismatch?

val eventListeners = new HashMap[Class[Event], ArrayBuffer[Event => Unit]]
def addEventListener[A <: Event](f: A => Unit)(implicit mf: ClassManifest[A]): A => Unit = {
eventListeners.getOrElseUpdate(mf.erasure.asInstanceOf[Class[Event]], ArrayBuffer[Event => Unit]()) += f
f
}
Is throwing:
error: type mismatch;
found : (A) => Unit
required: (this.Event) => Unit
eventListeners.getOrElseUpdate(mf.erasure.asInstanceOf[Class[Event]], ArrayBuffer[Event => Unit]()) += f
Why is it saying that it found (A) => Unit? The value of f is a function that is (Event) => Unit. Isn't A just a type parameter, not the signature?
Example call:
addEventListener { e:FooEvent => .... }
The class Function1 is contra-variant on its parameter. Ie, its type is Function1[-T, +R].
That means a function of Any => Unit is a subtype of Event => Unit, but for A a subtype of Event, A => Unit is a _super_type of Event => Unit.
Ergo, the problem. If you change the type parameter to A >: Event, it should work.
You are promising your ArrayBuffer that you will give it a function that can take any Event and turn it into a Unit (presumably doing something interesting along the way).
But you are giving it a function that can only take As, which may not encompass all Events. That is clearly not what you've promised, so the compiler complains.
You need to figure out what ought to happen in that case, and write code accordingly. For example, you could create a new function g that does nothing in case it receives an Event that, according to your class manifest, is not an A, and otherwise applies f. Or you could require all listeners to take events of all sorts, and be responsible themselves for throwing away the events that they don't want to bother with.
Edit: just to make things clearer with an example,
abstract class Fruit { def tasty: String }
class Banana extends Fruit { def tasty = "Yum!" }
abstract class SeededFruit extends Fruit {
def seedCount: Int
def tasty = "Mmm, mmm."
}
class Peach extends SeededFruit { def seedCount = 1 }
class Apple extends SeededFruit { def seedCount = 5 }
val tellAboutSeeds = (sf: SeededFruit) => println("There are "+sf.seedCount+"seeds")
val fruitTeller = new collection.mutable.ArrayBuffer[Fruit=>Unit]
fruitTeller += tellAboutSeeds // If this worked...
fruitTeller(0)(new Banana) // ...we'd be in trouble!