What is the best naming style for objects in class instances? - scala

http://docs.scala-lang.org/style/naming-conventions.html suggests that all objects are camelCase with a capital first letter except when attempting to mimic a package or a function. But what about mimicing a val?
class MyFrame extends javax.swing.JFrame {
object myBox extends javax.swing.Box(javax.swing.BoxLayout.X_AXIS) {
object myLabel extends javax.swing.JLabel {
import scala.collection.JavaConverters._
object myFont extends java.awt.Font(Map(java.awt.font.TextAttribute.FOREGROUND -> java.awt.Color.RED).asJava)
setFont(myFont)
}
add(myLabel)
}
add(myBox)
setSize(100, 60)
}
object Main {
def main(args: Array[String]) {
val myFrame = new MyFrame
myFrame.myBox.myLabel.setText("Hello, World!")
myFrame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE)
myFrame.setVisible(true)
}
}
Or
class MyFrame extends javax.swing.JFrame {
object MyBox extends javax.swing.Box(javax.swing.BoxLayout.X_AXIS) {
object MyLabel extends javax.swing.JLabel {
import scala.collection.JavaConverters._
object MyFont extends java.awt.Font(Map(java.awt.font.TextAttribute.FOREGROUND -> java.awt.Color.RED).asJava)
setFont(MyFont)
}
add(MyLabel)
}
add(MyBox)
setSize(100, 60)
}
object Main {
def main(args: Array[String]) {
val myFrame = new MyFrame
myFrame.MyBox.MyLabel.setText("Hello, World!") // Seems a bit weird to me
myFrame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE)
myFrame.setVisible(true)
}
}
Which one is better?

Just use camelCase for package objects.
for embedded objects in class use Upper camelCase.

Related

Is there any way to rewrite the below code using Scala value class or other concept?

I need to write two functions to get the output format and the output index for file conversion. As part of this, I wrote a TransformSettings class for these methods and set the default value. And in the transformer class, I created a new object of TransformSettings class to get the default values for each job run. Also, I have another class called ParquetTransformer that extends Transformer where I want to change these default values. So I implemented like below.
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer{
def getTransformSettings: TransformSettings = {
new TransformSettings
}
def posttransform(table: AWSGlueDDL.Table):Dateframe ={
val indexAccess = getTransformSettings.getOuputIndex(table: AWSGlueDDL.Table)
........
}
}
class ParquetTransformer extends Transformer{
override def getTransformSettings: TransformSettings = {
val transformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
}
}
Is there a way to avoid creating a brand new object of TransformSettings in Transfomer class every time this is called?
Also is there a way to rewrite the code using Scala value class?
As #Dima proposed in the comments try to make TransformSettings a field / constructor parameter (a val) in the class Transformer and instantiate them outside
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer(val transformSettings: TransformSettings) {
def posttransform(table: AWSGlueDDL.Table): DataFrame ={
val indexAccess = transformSettings.getOuputIndex(table: AWSGlueDDL.Table)
???
}
}
val parquetTransformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
class ParquetTransformer extends Transformer(parquetTransformSettings)
You don't seem to need value classes (... extends AnyVal) now. They are more about unboxing, not about life-cycle management. TransformSettings and Transformer can't be value classes because they are not final (you're extending them in class ParquetTransformer extends Transformer... and new TransformSettings { ... }). By the way, value classes have many limatations
https://failex.blogspot.com/2017/04/the-high-cost-of-anyval-subclasses.html
https://github.com/scala/bug/issues/12271
Besides value classes, there are scala-newtype library in Scala 2 and opaque types in Scala 3.

Scala Testing with Mock objects within objects

While Testing Called1.writeData and mocking using the traits, control is still going to the original implementation. Need help from experts.
object Caller1() {
def method1(param1:String, param2:Long) {
val param3=param1 //Some transformation
val param4=param2
Called1.writeData(param3, param4)
}
}
object Called1 extends Called1Trait {
val producer = Called2.createProducer
def writeData {
val data = createData(param1)
Called2.MethodA(...)
}
def createData(param1) {
// Some code
}
}
object Called2 extends Called2Trait {
def createProducer {
// Some code
}
def methodA {
// Some code
}
def methodB {
// methodA is used here
}
}
I have used mocking of the traits and using when and then to bypass the execution. Yet it is going to the methods. I have used any().
val CalledObject1Mock = mock[CalledObject1Trait]
val CalledObject2Mock = mock[CalledObject2Trait]
when(CalledObject1Mock.createProducer).thenReturn(ProducerMock)
when(CalledObject1Mock.writeData(any(),any())).thenReturn(true)
when(CalledObject1Mock.createData(any())).thenReturn(MockedData)
when(CalledObject2Mock.methodA(any(), any(), any())).thenReturn(true)
when(CalledObject2Mock.methodB(any(), any(), any())).thenReturn(true)
Called1.writeData(testParam1, testParam2) // this is failing
We have used scala Mockito. So do not intend to use any other framework.
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.BeforeAndAfterAll
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatestplus.mockito.MockitoSugar
import org.scalatest.matchers.should._
trait BaseTestSuite extends AnyFunSuite with BeforeAndAfterAll with Matchers with MockitoSugar {
The current design does not allow to test it by Mock.
You mocked the called objects but don't use them. The original Called1 does not know about mocked objects.
You should not mock a class under the testing.
To fix it I would suggest redesigning your classes this way:
class Caller1(called1: Called1Trait) {
def method1(param1:String, param2:Long) {
val param3=param1 //Some transformation
val param4=param2
called1.writeData(param3, param4)
}
}
class Called1(called2: Called2Trait) extends Called1Trait {
val producer = called2.createProducer
def writeData {
val data = createData(param1)
called2.methodA(...)
}
def createData(param1) {
// Some code
}
}
class Called2 extends Called2Trait {
def createProducer {
// Some code
}
def methodA {
// Some code
}
def methodB {
// methodA is used here
}
}
So, assume you want to test the Called1. The test will look like this:
val called2Mock = mock[Called2Trait]
when(called2Mock.methodA(any(), any(), any())).thenReturn(true)
when(called2Mock.methodB(any(), any(), any())).thenReturn(true)
val called1 = new Called1(called2Mock)
called1.writeData(testParam1, testParam2)
Now the called1 knows that called2 is mocked object and will call the mocked methodA().

How to access members of container class with same name? scala

I have something like this:
abstract class HaveData{
val data:String
}
class HD1 extends HaveData{
val data = "HD1 data"
}
class HD2 extends HaveData{
val data = "HD2 data"
object InnerHD extends HD1{
def prt = println(data)
}
}
I want to print "HD2 data" not "HD1 data", how to do that?
I may turn InnerHD to a class and provide data as a param but is there a better way?
For this kind of situations you can use a self-type, for this specific problem, you do not need to add a different type.
abstract class HaveData {
def data: String
}
class HD1 extends HaveData {
override val data = "HD1 data"
}
class HD2 extends HaveData { self => // Alias to this in the HD2 level.
override val data = "HD2 data"
object InnerHD extends HD1 {
def prt(): Unit = {
println(self.data)
}
}
}
(new HD2).InnerHD.prt()
// HD2 data
You can also use
def prt = println(HD2.this.data)

How to use a #Singleton from an Akka actor?

I am new to Dependency Injection and now when I migrated my application to Play 2.5.x I need to learn.
I have a singleton service looking something like this:
import javax.inject._
#Singleton
class WorkerService {
def doWork(work:String) {
...
}
}
I have an actor looking something like this:
import scala.concurrent.duration.DurationInt
import scala.language.postfixOps
import akka.actor._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scalaj.http._
import WorkerService
object PollActor {
def props(host: String) = Props(new PollActionActor(host))
}
// Actor that polls a host for information
class PollActor(host: String) extends Actor with ActorLogging {
// timer for poll
var timer: Cancellable = context.system.scheduler.schedule(0 second, 10 second, self, TimeStep())
// handle messages
override def receive = {
case TimeStep() =>
getWork match {
case Some(work:String) =>
// How to do this?: ChecklistService.doWork(work)
case None =>
}
}
def getWork = {
try {
Some(Http(host)
.option(HttpOptions.readTimeout(10000))
.option(HttpOptions.connTimeout(10000))
.asString.body)
} catch {
case _:Throwable =>
None
}
}
case class TimeStep()
}
And a controller something like this:
#Singleton
class Application #Inject() (implicit system: ActorSystem) extends Controller {
val pollActor = system.actorOf(PollActor.props("127.0.0.1"))
def index = Action {
pollActor ! TimeStep
}
}
How can I call WorkerService.doWork in the time step of the actor?
You probably should not create the actor in the Application class.
Try using a module to create your actor like this
class ApplicationConfigModule extends AbstractModule with AkkaGuiceSupport {
override def configure(): Unit = {
bindActor[PollActor]("poll-actor")
}
}
in your resources/application.conf put this
play.modules.enabled += "com.nowtv.platform.search.module.ApplicationConfigModule"
Then inject the service into your actor
class PollActor #Inject()(WorkerService: workerService) extends Actor
And inject the Actor into your Controller so you can use it there
#Singleton
class Application #Inject() (#Named("poll-actor") pollActor: ActorRef) extends Controller {

Factory method example in spark-shell giving error

I am unable to run below code in spark-shell repl. This is a reproduction from Scala cookbook example provided by Alvin Alexander
I get the error:
<console>:22: error: reference to Animal is ambiguous;
it is imported twice in the same scope by
import $VAL11.Animal
and import INSTANCE.Animal
val test = Animal("dog")
This works fine with Scala repl. Can you please tell me how I can make this example work on spark-shell as well?
Thanks a lot for your help!
trait Animal {
def speak
}
object Animal {
private class Dog extends Animal {
override def speak = {
println("woof")
}
}
private class Cat extends Animal {
override def speak { println("meow") }
}
def apply(s: String):Animal = {
if (s == "dog") return new Dog
else return new Cat
}
}
# repl
Animal("dog")
# compiling
object test {
def main(args: Array[String]){
Animal(args(0)).speak
}
}
As som-snytt pointed out, this is most likely a version of an existing scala bug.
Animal("dog") // show
results in something like this:
import $line15.$read.INSTANCE.$iw.$iw.Animal;
val $line15$read = $line15.$read.INSTANCE;
import $line15$read.$iw.$iw.Animal;
Note that Animal is imported twice. To fix this you can wrap your code in an object:
object test{
trait Animal {
def speak
}
object Animal {
private class Dog extends Animal {
override def speak = {
println("woof")
}
}
private class Cat extends Animal {
override def speak { println("meow") }
}
def apply(s: String):Animal = {
if (s == "dog") return new Dog
else return new Cat
}
}
}
Now, when you call test.Animal("dog") // show you get this instead:
val $line15$read = $line15.$read.INSTANCE;
import $line15$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.test;
Note that you get only one, more concise import.
As an interesting side note, if you run your first code and then the second, then test.Animal("dog") results in this:
import $line15.$read.INSTANCE.$iw.$iw.Animal;
val $line16$read = $line16.$read.INSTANCE;
import $line16$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.test;
Where the Animal import remains.