I am relatively new to scala so please bear me if I asked silly questions.
I have a requirement where I need to invoke a method run time.
I have a trait which is being extended by two classes
trait Animal {
def walk():DataFrame
}
This is extended by two classes.
class Dog(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
class Cat(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
Now from a config file I will get a list of these class names
Lets say like this
val animals = ["com.xy.Dog","com.xy.Cat"]
I need to invoke these classes and execute walk methods.
Can I do something like this?
animals.forEach{ animalString =>
val animalObject = Class.forName(animalString ).newInstance().asInstanceOf(Animal)
animalObject.walk
}
There are a few issues, let's take them one by one:
To build a list in scala you need to do:
val animals = List("com.xy.Dog", "com.xy.Cat")
The forEach method is actually foreach, so there's a small typo. Finally, when you call the newInstance you should get the appropriate constructor before that, otherwise it will use the default one.
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.getConstructor(classOf[DataFrame]) // Get the constructor for a DataFrame argument
.newInstance(dataframe) // Pass the dataframe instance
.asInstanceOf[Animal]
animalObject.walk
}
I've made a couple of small changes to the code for you to see it working. You can run the app to see the output:
class Dog extends Animal {
def walk(): Unit = { println("I'm a dog.") }
}
class Cat extends Animal {
def walk(): Unit = { println("I'm a cat.") }
}
object AnimalTest extends App {
val animals = List("com.xy.Dog", "com.xy.Cat")
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.newInstance()
.asInstanceOf[Animal]
animalObject.walk
}
}
Note that I've removed the constructor arguments here to easily build instances. The rest is about the same. I hope this helps you.
Related
Lets say I have the following structure:
src
- main
- scala
- model
- One.scala
- Two.scala
- main
- Test.scala
where Test.scala extends App and takes in a parameter:
object Test extends App {
val param: String = args.head
// Based on param, I want to use either One or Two?
}
// sbt run Two
How do i use definitions in either One.scala or Two.scala depending on the runtime value of param.
Appreciate any/all inputs..
Make sure that One and Two share some common interface, choose the instance of this interface at runtime, then import the members of the instance:
trait CommonInterface {
def foo(): Unit
}
object One extends CommonInterface { def foo() = println("1") }
object Two extends CommonInterface { def foo() = println("2") }
object Main extends App {
// check args etc...
val ci = if (args(0) == "one") One else Two
import ci._
// do something with `foo` here
foo()
}
I have a requirement to be able to count number of times AtomicReference[V].get is called in a class that has as field an array of wildcarded atomic references.
To that end, first, I've extended java's AtomicReference[V]:
import java.util.concurrent.atomic.{AtomicInteger => AInt, AtomicReference => ARef}
class MyAtomicReference[V] extends ARef[V]{
private val getCounter: AInt = new AInt(0)
def getAndListen(): V = {
getCounter.getAndIncrement()
super.get()
}
def counter(): Int = getCounter.get()
def resetCounter(): Unit = getCounter.set(0)
}
Then I've added trait AtomicRefCounter which declares the method that I would wish to invoke:
import simulacrum.typeclass
#typeclass trait AtomicRefCounter [R[_], T] {
def countGets(container: R[T]): Int
}
Lastly, I've defined a default AtomicArrayRefCounter in the object DefaultAtomicRefCounters:
object DefaultAtomicRefCounters {
implicit val arrayOfAtomicsTraverser = new AtomicRefCounter[Array, MyAtomicReference[_]] {
override def countGets(container: Array[MyAtomicReference[_]]): Int = container map(_.counter()) sum
}
}
Despite that when I try to call the traverseAtomics() on a corresponding array in a test, I do not see it (I am using Intellij IDEA):
behavior of "removeO1"
"method" should "remove an element from the pool with time O(1)" in new IntPoolBuilder {
import org.learningconcurrency.traditional_concurrency.helpers.DefaultAtomicRefCounters._
pool.buckets.countGet
}
A piece of advice on what I am missing would really help. Usage of simulacrum is not mandatory - if you feel you know how to solve this without it, I would love to hear that.
update:
This is how the buckets are implemented:
class Pool[T] {
type TimeStampedList = (List[T], Long)
val parallelism: Int = Runtime.getRuntime.availableProcessors * 32
val buckets = new Array[MyAtomicReference[TimeStampedList]](parallelism)
...
I think, you might have gotten wrong how implicits work.
If I read everything correctly, then in your code
implicitly[AtomicRefCounter[Array, MyAtomicReference[_]]].countGets(pool.buckets)
should work.
I you wanted to call countGets on the Array you should use the EnrichMyLibrary pattern.
object DefaultAtomicRefCounters {
implicit class RichArray(private underlying: Array[MyAtomicReference[_]] extends AnyVal {
def countGets: Int = underlying.map(_.counter()).sum
}
}
As disappointing as it is, I couldn't make it work with simulacrum annotation, so I've followed Sascha's advise. I just modified slightly his second example (I couldn't get it to work with implictly) so it compiles and works:
object TraditionalConcurrencyHelpers {
implicit class CountArrayAtomicGetsOps(wrapper: Array[MyAtomicReference[(List[Int], Long)]]) {
def countGets()(implicit atomicRefCounter: AtomicRefCounter[Array, MyAtomicReference[(List[Int], Long)]]): Int = atomicRefCounter.countGets(wrapper)
}
}
With this I have no problem calling countGets on the array:
behavior of "removeO1"
"method" should "remove an element from the pool with time O(1)" in new IntPoolBuilder {
import TraditionalConcurrencyHelpers._
import org.learningconcurrency.traditional_concurrency.helpers.DefaultAtomicRefCounters._
//call pool.removeO1 (not implemented yet)
pool.buckets.countGets() shouldEqual 1
}
I have a Scala application, where pretty much every object extends a specific trait, which holds all the main functions and variables used by pretty much the entire system.
I want to add a --testing flag to my app's command line variables, which will shift the the results of some of the functions in the trait.
Putting it simply, I'd like the variable accepted in the main to have an affect that alters something in the trait before it is extended by the objects - without sending it explicitly to all objects.
Any ideas how that can be performed?
I doubt you really want to dynamically modify a trait, and I am not sure if it possible that all your classes inheriting that trait would be affected. I don't know enough about the compiler and byte code.
A way to accomplish something similar would be to have your trait take a parameter, and make your trait act conditionally on the parameter.
trait Foo {
val testing: Boolean
def fn1(): Unit = {
if (testing) {
println("testing")
} else {
println("production")
}
}
}
class Bar(val testing: Boolean) extends Foo {
def fn2(): Unit = {
fn1()
}
}
new Bar(true).fn2()
new Bar(false).fn2()
Your question is broad and this is just my 5 cents.
Update
trait Foo {
def fn1(): Unit = {
if (Foo.testing) {
println("testing")
} else {
println("production")
}
}
}
object Foo {
var testing: Boolean = false
}
class Bar extends Foo {
def fn2(): Unit = {
fn1()
}
}
object SOApp extends App {
new Bar().fn2()
Foo.testing = true
new Bar().fn2()
}
Consider passing the 'testing' flag to the trait's initializer block like this:
trait MyTrait {
var testMode: Boolean = _
def doSomething(): Unit = {
if (testMode)
println("In Test Mode")
else
println("In Standard Mode")
}
}
// IMPORTANT: Your best bet would be to create some Config object
// that is loaded and initialized in a main method.
// Define test-specific Config class:
case class Config(testMode: Boolean) {
def isTestMode: Boolean = this.testMode
}
// Instantiate in main method:
val config = new Config(true)
// Later, extend the trait:
class MyObj extends MyTrait { testMode = config.isTestMode() }
// Then just invoke
new MyObject().doSomething()
I have Scala class which methods use a lot of regex. Each class method use some regex patterns.
Looking from the perspective of code modularity I should store those patterns in method:
class Bar {
def foo() {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
/*...*/
}
}
But this approach is quite inefficient. Patterns are recompiled on each method call.
I could move them directly to class:
class Bar {
val fooPatt1 = "[ab]+".r
val fooPatt2 = "[cd]+".r
/*...*/
}
but in case when I have 30 methods it looks ugly.
I ended up with some hybrid solution using val and anonymous function:
val z = {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
() => { /* ... */ }
}
but I am not sure if using val to store function have some drawbacks compared to def. Maybe there is other clean solution to store methods constants without polluting the class?
Using a val is perfectly fine. There might be a (very) small performance hit, but in most (99.9%) of the applications that's not a problem.
You could also create a class for the method
// The extends is not needed, although you might want to hide the Foo type
class Foo extends (() => ...) {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
def apply() = {
...
}
}
Then in the class:
class Bar {
val foo = new Foo
}
Another solution is using traits
trait Foo {
private lazy val patt1 = "[ab]+".r
private lazy val patt2 = "[cd]+".r
def foo() = ...
}
class Bar extends Foo with ...
Note that if you have different methods like that in a single class, it can be sign that the single responsibility principle is violated. Moving them to their own class (or trait) can be a solution for that problem as well.
I would put every method with the necessary regex in it's own Trait:
class Bar extends AMethod with BMethod
trait AMethod {
private val aPattern = """\d+""".r
def aMethod(s: String) = aPattern.findFirstIn(s)
}
trait BMethod {
private val bPattern = """\w+""".r
def bMethod(s: String) = bPattern.findFirstIn(s)
}
clean
separated
easy to test (object AMethodSpec extends Properties("AMethod") with AMethod ...)
I took into account Chris comment. Putting patterns to companion object is probably the most efficient approach but very unclean when we have more methods.
EECOLOR solution is less efficient but cleaner. Traits prevents recreating patterns on each method call. Unfortunately, scala do not use same compiled pattern accross multiple class instances:
(new X).patt1==(new X).patt1 // would be false.
I've combined those two approaches and instead traits I used objects.
object X {
object method1 {
val patt1 = "a".r
}
object method2 {
val patt1 = "a".r
}
}
class X {
def method1 = {
import X.method1._
patt1
}
def method2 = {
import X.method2._
patt1
}
}
(new X).method1 == (new X).method1 // true
(new X).method2 == (new X).method2 // true
Although this approach works, I think scala should provide some solution for that problem out of box. Patterns are the simplest example. We could have other immutable objects which initialization is much more expensive.
Extracting method internals somewhere outside is still unclear. It would be nice to do it like with lazy vals. Adding one modificator should ensure that value is instance only once across all instances and methods calls. It would be something like that:
def method1 {
static val x = new VeryExpensiveObject
}
Parametrized components work well with the cake pattern as long as you are only interested in a unique component for each typed component's, example:
trait AComponent[T] {
val a:A[T]
class A[T](implicit mf:Manifest[T]) {
println(mf)
}
}
class App extends AComponent[Int] {
val a = new A[Int]()
}
new App
Now my application requires me to inject an A[Int] and an A[String], obviously scala's type system doesn't allow me to extends AComponent twice. What is the common practice in this situation ?
I think the AComponent doesn't need to be parameterized itself. So loose the type parameter and change this into
trait AComponent {
val aInt: A[Int]
val aStr: A[String]
class A[T](implicit mf:Manifest[T]) {
println(mf)
}
}
class App extends AComponent {
val aInt = new A[Int]()
val aStr = new A[String]()
}
if you want to be able to provide instances for Int and String