Is it possible to extend a method within an extended scala class? - scala

Assume I have the following scala classes, is it possible to extend a function on SecondClass and add more code to it? (possibly chained to another function within the function i'd like to extend)
package io.gatling.http.check
class FirstClass {
def login() = {
exec(http("Login")
.post("anonymous/login")
.body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
}
}
I would like to extend the login function with the following (.check(status is 200)
class SecondClass extends FirstClass {
def login() = {
.check(status is 200))
}
}
Is that possible?

The syntax you're looking for is
class X {
def go(a: Int) = ???
}
class Y extends X {
override def go(a: Int) = {
val u = super.go(a)
// do things with `u` and return whatever
}
}
You'll need to do a little refactoring to get your code in this shape. I envisage
class FirstClass {
def body = ElFileBody("rest/UserAnonymousLogin.json")
// stuff that calls `body`
}
class SecondClass {
override def body = super.body.check(status is 200)
// no need to redefine stuff as it's inherited from `FirstClass`
}

Given checks method accepts a variable number of HttpCheck, that is, HttpCheck*
def check(checks: HttpCheck*): HttpRequestBuilder
consider refactoring FirstClass to
class FirstClass {
def login(checks: HttpCheck*) = {
exec(http("Login")
.post("anonymous/login")
.body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
.check(checks: _*)
)
}
}
Note how by default we pass no checks when calling (new FirstClass).login().
Now derived classes could pass in a checks to be performed like so
class SecondClass extends FirstClass {
def loginWithStatusCheck() = {
super.login(status is 200)
}
}
Note we are not actually overriding FirstClass.login here.
Another approach instead of overriding could be functional composition, for example, we break down the problem into smaller functions
val buildClient: String => Http = http(_)
val buildPostRequest: Http => HttpRequestBuilder = _.post("anonymous/login").body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
val checkStatus: HttpRequestBuilder => HttpRequestBuilder = _.check(status is 200)
and then compose them
exec((buildClient andThen buildPostRequest andThen checkStatus)("Login"))
Now we can simply add further steps to the composition instead of worrying about class hierarchies and overriding.

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.

Implement a new feature with loose coupling

trait paymentTasks{
def calculatePayment()
def getData()
}
class paymentcalculator{
override def calculatePayment() ={
//Implementation }
}
override defGetData() ={
}
}
How do I call the method to keep the code less dependent and don't want to use new keyword
class MyApp{
val payment = new paymentcalculator
//I don't want to instantiate like this wants this to be decoupled
}
Please suggest how do I implement this ,also new Changes in future can be done without changing existing code.Also,suggest if doing this functionally would be more effective
If you want compile-time selection then just put the code into an object
trait PaymentTasks {
def calculatePayment()
def getData()
}
object PaymentCalculator extends PaymentTasks {
def calculatePayment() = ???
def getData() = ???
}
class MyApp {
val payment = PaymentCalculator.calculatePayment()
}
If you want run-time selection than the best way is to use dependency injection and create the payment object at the top level and pass it down to the code that requires it.
object SimplePaymentCalculator extends PaymentTasks
object ComplexPaymentCalculator extends PaymentTasks
class MyApp {
def myImplementation(tasks: PaymentTasks) = {
val payment = tasks.calculatePayment()
}
val payment =
if (???) {
SimplePaymentCalculator
} else {
ComplexPaymentCalculator
}
myImplementation(payment)
}

Scala mocking the behaviour

When I mock the particular object method is executing the actual behavior.
The expected output should be 10since I mocked the Calculate.add and returning the result as 10
trait Base {
def add (parm1:Int, parm2:Int): Int
def fetc ():Any
def compute(): Any
}
object Calculate extends Base {
def add(parm1:Int, parm2:Int):Int = {
fetc()
compute
}
def fetc ():Any = {
// Making some api1 call
}
def compute ():Any = {
// Making some api2 call
}
}
object Engine {
def execute():any{
Calculate.add(10, 20)
}
}
Test
class TestEngine extends MockFactory {
it should "compute" in {
val res1:Int = 10
val calculate: Base = stub[Base]
val data = (calculate.add _).when(10, 20).returns(res1);
Engine.execute() // ExpectedOutput should be 10(res1),Since the I mocked the add method and returning the 10 value. Should not call the Calculate object fetch, compute behaviour.
}
}
Though Calculate is mocked & add method has been stubbed, still the actual functionality of add will be executed, since in Engine.execute method Calculate object reference is used to access the add method also Calculate is itself an object, thus the actual code will be executed.
object Engine {
def execute():any{
Calculate.add(10, 20)
}
}
Simple solution to mocked calculate in Engine.execute could be instead of using Calculate object passed a base variable as method parameter.
object Engine {
def execute(base: Base): Int = {
base.add(10, 20)
}
}
class TestEngine extends MockFactory {
it should "compute" in {
val res1: Int = 10
val calculate: Base = stub[Base]
val data = (calculate.add _).when(10, 20).returns(res1);
//mocked_calculate
Engine.execute(mocked_calculate)
}
}

specs2 After method runs before the example

I have the following test:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
class Context extends mutable.BeforeAfter with mutable.Around {
override def apply[T : AsResult](a: =>T): Result = {
lazy val result = super[Around].apply(a)
super[BeforeAfter].apply(result)
}
override def delayedInit(x: => Unit): Unit = around { try { before; x; Success() } finally { after }}
#Resource var barReader : BarReader = _
val bar = barReader.someBar
override def before : Any = { //some stuff}
def after: Any = {
bar = None
}
override def around[T : AsResult](t: =>T) = {
//spring context injection logic
AsResult.effectively(t)
}
}
}
}
I expect this test to pass but in reality what happens is that because of the delayed init, the after runs before the example. If I change the Context to a trait I lose the delayed init functionality. Is this a bug or am I doing something wrong?
**Edited:
This example will throw an NPE when the Context is a trait. What I expect to happen is that because of the delayed-init, the Context's constructor, which consequentially means the barReader.someBar will run only after the barReader has been injected.
Thanks
Netta
You should use a trait instead of a class for Context. If you use a class, delayedInit (hence after) will be triggered twice. Once for the body of the Context class and another time for the body of the anonymous class new Context. With a trait you don't get such a behavior:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
trait Context extends mutable.After {
var bar : Option[String] = Some("bar")
def after: Any = bar = None
}
}
Simple answer, looks like this can't be done.

Scala: Can I reproduce anonymous class creation with a factory method?

As far as I understand it, Scala creates an anonymous class if I create a class using the new keyword and follow the class name with a constructor:
class MyClass {
def doStuff() {
// ...
}
}
val mc = new MyClass {
doStuff()
}
The nice thing being that all the code in the constructor is in the scope of the new object.
Is there a way I can reproduce this syntax where the class is created by a factory method rather than the new keyword? i.e. make the following code work:
val mf = new MyFactory
val mc = mf.MyClass {
doStuff()
}
I can't find a way to do it but Scala has so much to it that this might be pretty easy!
Using an import as suggested by #Ricky below I can get:
val mf = MyFactory;
val mc = mf.MyClass
{
import mc._
doStuff()
}
(Where the blank line before the block is needed) but that code block is not a constructor.
You can do this, but you still have to keep the new keyword, and create the nested class as a path-dependent type:
class Bippy(x: Int) {
class Bop {
def getIt = x
}
}
val bip = new Bippy(7)
val bop = new bip.Bop
bop.getIt // yields 7
val bop2 = new bip.Bop{ override def getIt = 42 }
bop2.getIt // yields 42
I don't think it's possible. However, a common pattern is to add a parameter to factory methods which takes a function modifying the created object:
trait MyClass {
var name = ""
def doStuff():Unit
}
class Foo extends MyClass {
def doStuff() { println("FOO: " + name) }
}
trait MyClassFactory {
def make: MyClass
def apply( body: MyClass => Unit ) = {
val mc = make
body(mc)
mc
}
}
object FooFactory extends MyClassFactory {
def make = new Foo
}
You can then create and modify instance with a syntax close to your example:
val foo = FooFactory { f=>
f.name = "Joe"
f.doStuff
}
It sounds like you're just looking to mix in a trait. Instead of calling myFactoryMethod(classOf[Foo]] which ideally would do (if Scala permitted it):
new T {
override def toString = "My implementation here."
}
you can instead write
trait MyImplementation {
override def toString = "My implementation here."
}
new Foo with MyImplementation
However, if you are just looking to get the members of the new object accessible without qualification, remember you can import from any stable identifier:
val foo = new Bar
import foo._
println(baz) //where baz is a member of foo.