I've got a class from a library (specifically, com.twitter.finagle.mdns.MDNSResolver). I'd like to extend the class (I want it to return a Future[Set], rather than a Try[Group]).
I know, of course, that I could sub-class it and add my method there. However, I'm trying to learn Scala as I go, and this seems like an opportunity to try something new.
The reason I think this might be possible is the behavior of JavaConverters. The following code:
class Test {
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
does not compile, because there is no asScala method on Java's ArrayList. But if I import some new definitions:
class Test {
import collection.JavaConverters._
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
then suddenly there is an asScala method. So that looks like the ArrayList class is being extended transparently.
Am I understanding the behavior of JavaConverters correctly? Can I (and should I) duplicate that methodology?
Scala supports something called implicit conversions. Look at the following:
val x: Int = 1
val y: String = x
The second assignment does not work, because String is expected, but Int is found. However, if you add the following into scope (just into scope, can come from anywhere), it works:
implicit def int2String(x: Int): String = "asdf"
Note that the name of the method does not matter.
So what usually is done, is called the pimp-my-library-pattern:
class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
implicit def foo2Better(x: Foo) = new BetterFoo(x)
That allows you to call coolMethod on Foo. This is used so often, that since Scala 2.10, you can write:
implicit class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
which does the same thing but is obviously shorter and nicer.
So you can do:
implicit class MyMDNSResolver(x: com.twitter.finagle.mdns.MDNSResolver) = {
def awesomeMethod = { ... }
}
And you'll be able to call awesomeMethod on any MDNSResolver, if MyMDNSResolver is in scope.
This is achieved using implicit conversions; this feature allows you to automatically convert one type to another when a method that's not recognised is called.
The pattern you're describing in particular is referred to as "enrich my library", after an article Martin Odersky wrote in 2006. It's still an okay introduction to what you want to do: http://www.artima.com/weblogs/viewpost.jsp?thread=179766
The way to do this is with an implicit conversion. These can be used to define views, and their use to enrich an existing library is called "pimp my library".
I'm not sure if you need to write a conversion from Try[Group] to Future[Set], or you can write one from Try to Future and another from Group to Set, and have them compose.
Related
In java and c#,I can write this:
class Tree {
Tree left;
Tree right;
}
but in scala:
class Tree{
val left:Tree
val right:Tree
}
I need to add abstract for class,or write:
val left:Tree=new Tree()
I can write this:
trait Tree{
val left:Tree
val right:Tree
}
but why if I use class,I "have to"and abstract?I don't think it's a good design
Thanks!
The reason you can write
class Tree {
Tree left;
Tree right;
}
in Java and C# is because the fields are initialized to null by default (or to 0, etc. depending on the type). Scala's designers decided this is a bad idea and you need to initialize them. So the approximate Scala equivalent is
class Tree {
// note, not val
var left: Tree = null
var right: Tree = null
}
which is legal (but probably not something you actually want to use).
but why if I use class,I "have to"and abstract?
You have to mark your class with the abstract keyword because your class is abstract. It cannot possibly be instantiated.
I don't think it's a good design
Good design is subjective. The designers of Scala thought that being explicit in this case, rather than making the class automatically abstract was good design. I would guess that the majority of the Scala community agrees with them.
You disagree, and that is perfectly okay.
It happened because scala sometimes considers val and def as method like declarations. Let me elaborate, please, for instance, we have the next Scala example:
class Example {
val a: String = "example"
}
val example = new Example()
println(example.a)
You may see that a declared as a field. Unlike Java, we can change this declaration easily to def and everything remains compiling:
class Example {
def a: String = "example"
}
val example = new Example()
println(example.a)
In the case of Java (not sure about C# I've never worked with it), if you would like to access the field over getter method, you will need to change all invocation places from field to method access.
Now, you can consider val as let's say sort of eager cached def version - if so then declaring val without actually value assignment implicitly considered by compiler as declaring method without implementation and that's why compiler says Tree is an abstract class - because left and right has no values, hence they are abstract. In order to make it non-abstract, you need to assign a value to fields or use var if you would like to proceed with mutable structure, e.g.:
class Example {
val a: String = "example"
}
val example = new Example()
println(example.a)
Scatie: https://scastie.scala-lang.org/bQIcVNk9SN6qJhbL32SMUQ
While learning Scala, I came across interesting concept of companion object. Companion object can used to define static methods in Scala. Need few clarifications in the below Spark Scala code in regard of companion object.
class BballStatCounter extends Serializable {
val stats: StatCounter = new StatCounter()
var missing: Long = 0
def add(x: Double): BballStatCounter = {
if (x.isNaN) {
missing += 1
} else {
stats.merge(x)
}
this
}
}
object BballStatCounter extends Serializable {
def apply(x: Double) = new BballStatCounter().add(x)
}
Above code is invoked using val stat3 = stats1.map(b=>BballStatCounter(b)).
What is nature of variables stats and missing declared in the
class? Is it similar to class attributes of Python?
What is the significance of apply method in here?
Here stats and missing are class attributes and each instance of BballStatCounter will have their own copy of them just like in Python.
In Scala the method apply serves a special purpose, if any object has a method apply and if that object is used as function calling notation like Obj() then the compiler replaces that with its apply method calling, like Obj.apply() .
The apply method is generally used as a constructor in a Class Companion object.
All the collection Classes in Scala has a Companion Object with apply method, thus you are able to create a list like : List(1,2,3,4)
Thus in your above code BballStatCounter(b) will get compiled to BballStatCounter.apply(b)
stats and missing are members of the class BcStatCounter. stats is a val so it cannot be changed once it has been defined. missing is a var so it is more like a traditional variable and can be updated, as it is in the add method. Every instance of BcStatCounter will have these members. (Unlike Python, you can't add or remove members from a Scala object)
The apply method is a shortcut that makes objects look like functions. If you have an object x with an apply method, you write x(...) and the compiler will automatically convert this to x.apply(...). In this case it means that you can call BballStatCounter(1.0) and this will call the apply method on the BballStatCounter object.
Neither of these questions is really about companion objects, this is just the normal Scala class framework.
Please note the remarks in the comments about asking multiple questions.
Can Scala macros be used to make implementers of a method in a trait invoke the super method. For instance like this:
trait Super {
//some macro magic here: list = super.list ++ child.list
def list: List[String] = List("ein", "zwei", "DIE")
}
class Sub extends Super {
override def list: List[String] = List("4", "5")
}
object Testy extends App {
println(new Sub().list) //List(ein, zwei, DIE, 4, 5)
}
Update:
See comment from #Sergey below - this is not really doable with macros.
I don't think you need macros in this particular case. In order to enforce some data from a superclass' method to be added to all results of implementing methods in any subclass, the preferred approach would be to use a template method. Make a final def performing the addition of the fixed part and an abstract def declaring the variable part, like so:
trait Super {
protected def additionalList: List[String]
final def list: List[String] = List("ein", "zwei", "DIE") ++ additionalList
}
class Sub extends Super {
protected val additionalList = List("4", "5")
}
object Testy extends App {
println(new Sub().list) // List(ein, zwei, DIE, 4, 5)
}
Update: If, however, you need exactly the behavior as specified in the original question, then you're out of luck, I fear: a macro can only affect what it immediately wraps, e.g. a def macro can only transform what is passed into the method, and an annotation macro can only transform its immediate annottee, be it a class, a field, a method, etc. There's no way for a macro to enforce rules on code which doesn't even know about the macro. So basically you have two options: either make your users call super manually, or write an annotation macro and have your users annotate their subclasses with it. Both of these options are easy to omit, unfortunately.
A minimized example is the following:
object Main extends App {
def f = {
def giveMeBigDecimal(x: String) = BigDecimal(x)
def giveMeBigDecimal(x: Double) = BigDecimal(x)
(giveMeBigDecimal("1.0"), giveMeBigDecimal(1.0))
}
}
Scala 2.9.2 compiler keep saying me that method giveMeBigDecimal is defined twice
I know how can I workaround this, but curious why such limitation exists.
It's a Scala's implementation detail which (unfortunately) made its way to the spec. Scala implements local methods as variables with closure type and it isn't allowed to have two variables with the same name in the same method.
I want to create a method that generates an implementation of a trait. For example:
trait Foo {
def a
def b(i:Int):String
}
object Processor {
def exec(instance: AnyRef, method: String, params: AnyRef*) = {
//whatever
}
}
class Bar {
def wrap[T] = {
// Here create a new instance of the implementing class, i.e. if T is Foo,
// generate a new FooImpl(this)
}
}
I would like to dynamically generate the FooImpl class like so:
class FooImpl(val wrapped:AnyRef) extends Foo {
def a = Processor.exec(wrapped, "a")
def b(i:Int) = Processor.exec(wrapped, "b", i)
}
Manually implementing each of the traits is not something we would like (lots of boilerplate) so I'd like to be able to generate the Impl classes at compile time. I was thinking of annotating the classes and perhaps writing a compiler plugin, but perhaps there's an easier way? Any pointers will be appreciated.
java.lang.reflect.Proxy could do something quite close to what you want :
import java.lang.reflect.{InvocationHandler, Method, Proxy}
class Bar {
def wrap[T : ClassManifest] : T = {
val theClass = classManifest[T].erasure.asInstanceOf[Class[T]]
theClass.cast(
Proxy.newProxyInstance(
theClass.getClassLoader(),
Array(theClass),
new InvocationHandler {
def invoke(target: AnyRef, method: Method, params: Array[AnyRef])
= Processor.exec(this, method.getName, params: _*)
}))
}
}
With that, you have no need to generate FooImpl.
A limitation is that it will work only for trait where no methods are implemented. More precisely, if a method is implemented in the trait, calling it will still route to the processor, and ignore the implementation.
You can write a macro (macros are officially a part of Scala since 2.10.0-M3), something along the lines of Mixing in a trait dynamically. Unfortunately now I don't have time to compose an example for you, but feel free to ask questions on our mailing list at http://groups.google.com/group/scala-internals.
You can see three different ways to do this in ScalaMock.
ScalaMock 2 (the current release version, which supports Scala 2.8.x and 2.9.x) uses java.lang.reflect.Proxy to support dynamically typed mocks and a compiler plugin to generate statically typed mocks.
ScalaMock 3 (currently available as a preview release for Scala 2.10.x) uses macros to support statically typed mocks.
Assuming that you can use Scala 2.10.x, I would strongly recommend the macro-based approach over a compiler plugin. You can certainly make the compiler plugin work (as ScalaMock demonstrates) but it's not easy and macros are a dramatically superior approach.