Scala: Companion object with arguments - scala

I am looking for a way to initialize a companion object with arguments. I tried this, it has the risk for re-instantiation.
private[mypackage] class A(in:Int) {
def method = {}
}
object A {
var singleton: Option[A] = None
def getInstance(): A = {
if(singleton.isDefined)
singleton.get
else {
throw InitializationException("Object not configured")
}
}
def getInstance(in:Int): A = {
singleton = Some(new A(in))
singleton.get
}
}
Is there a better way?

Pure Scala way
Scala allows you to create a singleton object of a type using object keyword. Scala ensures only one instance of A is available in the system.
private[myPackage] object A {
val configValue = Config.getInt("some_value")
def fn: Unit = ()
}
type of A object
scala> object A {}
defined object A
scala> :type A
A.type
more about singleton objects in scala Explanation of singleton objects in Scala
Guice Annotations
import com.google.inject.Singleton
#Singleton
class A (val value: Int) {
def fn: Unit = ()
}
Classic Java way
Use synchronized keyword to protect the getInstance from creating more than one object when called. of course constructor of the class has to be private

You can use a lazy val to delay creation of your singleton, and base it on a var that should be updated once during start-up sequence:
object A {
// will be instantiated once, on first call
lazy val singleton: A = create()
private var input: Option[Int] = None
// call this before first access to 'singleton':
def set(i: Int): Unit = { input = Some(i) }
private def create(): A = {
input.map(i => new A(i))
.getOrElse(throw new IllegalStateException("cannot access A before input is set"))
}
}

Related

Scala - why cannot use trait from object

I have created a simple application with singleton object which contains local traits:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
}
And now, in Main object, I would like to do something like this:
object Main extends App {
val singleton = Singleton.FirstTrait//cannot do this
}
But I cannot do this (compile error). Why? Why I have not an access into this local trait? If I change Singleton object into:
object Singleton {
trait FirstTrait {
val func1 = (i: Int) => i * 2
}
trait SecondTrait {
val func2 = (s: String) => s
}
trait ThirdTrait {
val func3 = () => println("Func 3")
}
object FirstObject extends FirstTrait {
println(func1)
}
}
Main works well and program compiles. But I call another singleton object from Singleton, not a trait. I understand that trait cannot be instanced, but I think it is not a solution for it, because I have also a simple ScalaTest test name, which looks like
"Singleton" should "test it" in Singleton.FirstTrait{...}
and here I have an access into FirstTrait. So why I cannot use it in normal code?
I cannot understand it well. Maybe I am an idiot, but if someone could explain it to me well, I would be greatful.
It's a trait so you'll need to "instantiate" it properly:
val singleton = new Singleton.FirstTrait {}
// singleton: Singleton.FirstTrait = $anon$1#5e97da56
Note that technically a trait cannot be instantiated. The above expression is an instantiation of the anonymous class that extends the trait.
Singleton.FirstTrait is a type, not a value. You can't write
val singleton = Singleton.FirstTrait
any more than you can write
val singleton = Int
val singleton = String
etc. Traits and classes can have companion objects (objects with the same name), but FirstTrait obviously doesn't have one.
You can use it as a type, e.g.
def foo(x: Singleton.FirstTrait) = {}
val x: Singleton.FirstTrait = new Singleton.FirstTrait {}

Why scala serializability differs in case classes with same constructor parameter types?

Why am I able to serialize this:
// Serialize: OK
case class ClassWithType2[T:TypeTag](x:T) {
val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}
... but not this
class TypeAware[T:TypeTag]() {
val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}
// Serialize: FAIL.
// No valid constructor for ClassWithType1
// in: java.io.ObjectStreamClass.checkDeserialize
case class ClassWithType1[T:TypeTag](x:T) extends TypeAware[T]
Both seem have the same constructor type prototype:
[T:TypeTag](x:T)
and both extend scala.Serializable and java.io.Serializable
val s1:Serializable = ClassWithType1(x=123)
val s2:Serializable = ClassWithType2(x=123)
val s3:java.io.Serializable = ClassWithType1(x=123)
val s4:java.io.Serializable = ClassWithType2(x=123)
Its there a way to implement TypeAware subclasses that:
avoid having to declare tpe in every subclass (as ClassWithType2 does)?
allows the object to be serialized
Here's the test harness
class TypesTest {
#Test
def serializeTypeTest(): Unit = {
val obj2:Object = ClassWithType2(x=123)
Util.copyBySerialization(obj2) // Success!
val obj1:Object = ClassWithType1(x=123)
Util.copyBySerialization(obj1) // Fail
}
}
object Util {
def toJavaClass[T:TypeTag]: Class[_] = {
val tpe = typeOf[T]
runtimeMirror(tpe.getClass.getClassLoader).runtimeClass(tpe.typeSymbol.asClass)
}
def copyBySerialization[T](obj: T): T = deserialize(serialize(obj))
def serialize[T](obj: T): Array[Byte] = {
val byteOut = new ByteArrayOutputStream()
val objOut = new ObjectOutputStream(byteOut)
objOut.writeObject(obj)
objOut.close()
byteOut.close()
byteOut.toByteArray
}
def deserialize[T](bytes: Array[Byte]): T = {
val byteIn = new ByteArrayInputStream(bytes)
val objIn = new ObjectInputStream(byteIn)
val obj = objIn.readObject().asInstanceOf[T]
byteIn.close()
objIn.close()
obj
}
}
Just quoting the Javadoc:
To allow subtypes of non-serializable classes to be serialized, the
subtype may assume responsibility for saving and restoring the state
of the supertype's public, protected, and (if accessible) package
fields. The subtype may assume this responsibility only if the class
it extends has an accessible no-arg constructor to initialize the
class's state. It is an error to declare a class Serializable if this
is not the case. The error will be detected at runtime.
The ctor for TypeAware includes the implicit parameter.
Edit: one idea is to make the type tag a member. Or similar. It doesn't save as much syntax.
abstract class TypeAware {
protected def tt: TypeTag[_]
def tpe:java.lang.reflect.Type = Util.toJavaClass(tt)
}
case class ClassWithType1[T](x:T)(implicit val tt: TypeTag[T]) extends TypeAware
Edit, more linx:
tech page
faq
your question

Preventing the creation of anonymous classes from traits, without an enclosing object

Suppose I have the following trait and object:
trait NoAnon {
val i: Int
}
object NoAnon {
def create = new NoAnon {
val i = 123
}
}
I would like to prevent anonymous instances of NoAnon from being created outside of the companion object. ie. only create in this example should be allowed to do this. I can enclose these within another object, and make the trait private to that object to accomplish this:
object Ctx {
private[Ctx] trait NoAnon {
val i: Int
}
object NoAnon {
def create = new Ctx.NoAnon {
val i = 123
}
}
}
Is it possible to do this without the enclosing object Ctx?
To be a little more clear, can traits mimic the functionality of a private abstract class constructor? That is, the following example, except with a trait.
abstract class NoAnon private[NoAnon] {
val i: Int
}
object NoAnon {
def create = new NoAnon {
val i = 123
}
}
Maybe you could use a class with a private constructor and extend that with your trait. You can even nest that class in the companion object:
trait NoAnon extends NoAnon.type#NoAnonCheck {
val i: Int
}
object NoAnon {
class NoAnonCheck private[NoAnon]
def create = new NoAnon {
val i = 1
}
}
Then if you tried:
new NoAnon { val i = 2 }
You get:
error: constructor NoAnonCheck in class NoAnonCheck cannot be accessed in <$anon: NoAnonCheck with NoAnon>
But you can use NoAnon.create. Other than adding something like this, I don't think there is currently a pure way to do this in Scala.
Of course as you know and as mentioned in the comments, the other options are to make the the trait private to the scope of an enclosing object or package.

Creating instance type after filter

I have a simple class which extends IndexedSeq[MyType]
class MyClass(someName: String, values: Iterable[MyType]) extends IndexedSeq[MyType] {
val name = someName
val rows = values.toVector
....
}
This works fine, allowing me to call all the standard collection methods on this object, filter, map etc and returning me the results as an IndexedSeq[MyType].
What I would like is for the results be returned as a new instance of MyClass or a boilerplate free way of doing this so I don't require the additional manual step each time of creating a new MyClass. EG:
val results = myClassInstance.filter(t => t)
val newMyClass = new MyClass(myClassInstance.name, results)
Is there any way of simplifying and doing something like the following, given that I need access to the original myClassInstance to copy the name value from it to the new object.
val newMyClass = myClassInstance.filter(t => t).toMyClass
Thanks
I've figured out the solution by extending IndexedSeqLike[DataRow, DataView] and implementing a builder in the companion object. So far this seems to do exactly what I was after without needing passthough calls.
class MyClass(someName: String, values: Iterable[MyType])
extends IndexedSeq[MyType]
with IndexedSeqLike[MyType, MyClass] {
val name = someName
val rows = values.toVector
// Supply a builder method which will get used on filter, reverse etc,
override def newBuilder: mutable.Builder[MyType, MyClass] =
MyClass.newBuilder(name)
....
}
Then in the companion object, add the following...
object MyClass {
// Builder for a new MyClass instance.
def newBuilder(name: String): mutable.Builder[MyType, MyClass] =
Vector.newBuilder[MyType] mapResult (vector => new MyClass(name, vector))
}
Now the following work as required :
val filteredData: MyClass = myClass.filter(f => f)
val reversedData: MyClass = myClass.reverse
Are you sure you need to inherit from IndexedSeq?
If you need only filter & map function in your class, you can implement them, without overriding IndexedSeq
class MyClass(name: String, values: Iterable[MyType]) {
def filter(f: MyType => Boolean): MyClass = {
new MyClass(name, values.filter(f))
}
def map(f: MyType => MyType): MyClass = {
new MyClass(name, values.map(f))
}
}
or If you really really need to override IndexedSeq, you can add explicit filter method to your class
class MyClass(name: String, values: Iterable[MyType]) extends IndexedSeq[MyClass] {
def filterClass(f: MyType => Boolean): MyClass = {
new MyClass(name, values.filter(f))
}
}
Or another option
class MyClass(name: String, values: Iterable[MyType]) extends IndexedSeq[MyClass] {
def copyWith(f: Iterable[MyType] => Iterable[MyType]): MyClass = {
new MyClass(name, f(values))
}
}
MyClass.copyWith(_.filter(...))
MyClass.copyWith(_.filterNot(...))
MyClass.copyWith(_.map(...))

How to get a reference to the actor instance that runs a function?

I have a program structured as follows:
abstract class OuterClass
{
class InnerClass extends Actor
{
loop
{
react
{
case m: T => someFunction(m)
}
}
def someFunction(m: T)
{
...search function map for specific function...
specificFunction()
}
...extra methods here...
}
var functionmap=scala.sollection.mutable.Map.empty[String,()=>String]
var actorpool: ArrayBuffer[Actor]=new ArrayBuffer(0)
def main(args: Array[String])
{
...create X actors and add them to the pool...
populatefunctionmap
}
def populatefunctionmap() //defined elsewhere
}
class RunMe extends OuterClass
{
def populatefunctionmap()
{
...add some functions to the map...
}
}
The problem I have is that I would like to make use of the extra functions available within the actor instance that runs my functionmap functions. When I've tried using this it refers to the extending RunMe class. Using self just results in a not found: value self compiler error.
Is what I want to do possible? If so, how?
A couple of points I'd like to make about your code:
functionmap is both a var and mutable Map. Typically you only need it to be one or the other; not both.
Same goes for actorpool.
Access to shared, mutable state violates the design principles of the actor model.
Given the skeleton you provided, I'm assuming that you don't need to change the functionmap after it's been initialized. Instead of making it a mutable var, make it an immutable val.
You can do that by either an abstract val (shown here), or by a constructor parameter.
abstract class OuterClass {
class InnerClass extends Actor {
def act() {
loop {
react {
case m: T => someFunction(m)
}
}
}
def someFunction(m: T) {
// ...search functionmap for specific function...
for (specificFunction <- functionmap.get(key)) {
specificFunction()
}
}
}
// abstract val
val functionmap: Map[String, () => String]
val actorpool: ArrayBuffer[Actor]=new ArrayBuffer(0)
def main(args: Array[String]) {
// ...create X actors and add them to the pool...
}
}
class RunMe extends OuterClass {
val functionmap = {
// ...build the function map...
}
}
If you need to change functionmap after the actors are created, then InnerClass needs to have a var which holds their own functionmap, which you change by sending messages to the actors.
If I understand correctly, your question has nothing to do with Actors. It boils down to:
abstract class Outer {
class Inner {
def innerf = 42
}
}
class RunMe extends Outer {
val inst = new Inner
def ref = inst.innerf
}
scala> (new RunMe).ref
res0: Int = 42
scala> val r = new RunMe
scala> (new r.Inner).innerf
res1: Int = 42
The inner class's methods are only available on an instance of that inner class, so you need to start by making some instances.
If you'd like to access methods of InnerClass from the functions in functionmap, then it should be of type InnerClass => String, so you have the instance you want to call methods on.