I want to do something I feel is simple, but I cannot figure out the way to do it. It is the following: according to some String variable I want to create an object of some specific type. However, the underlying objects have the same methods, so I want to be able to use this object outside the if block where the object is created. What is the best possible way to achieve it?
To ilustrate my need, here is the code:
var model = null
if (modelName == "KMeans") {
model = new KMeans()
} else if (modelName == "BisectKMeans") {
model = new BisectingKMeans()
}
model.setK(k)
model.fit(data)
Both KMeans and BisectingKMeans have the setK and fit methods. I want to create the object inside the if block but use the object outside it. This code gives an error when declaring the variable, as I'm not initializing it.
I've tried generic objects with a case class and declaring the variable as Any type, but cannot manage to get this to work, what is the best way to achieve what I'm looking for?
Scala actually does allow you to do this with structural types:
type Model = {
def setK(k: Int): Any
// the links in the question don't have a fit method
def fit(???): ???
}
val model: Model = if (modelName == "KMeans") { new KMeans() } else { model = new BisectingKMeans() }
model.setK(k)
model.fit(data)
But it isn't particularly recommended to use if you have better alternatives due to use of reflection. I would simply call setK and fit inside the blocks in this specific case; or if not, create your own wrappers of KMeans and BisectingKMeans which implement a common trait.
create your own interface and adapt the implementation to that. This will also work if you need to unify very different classes (different method names for example) into a common interface. Using implicit def is not required but does save the wrapping part at the call site
trait Model {
def setK(): ??? // fill in your type
def fit(): ??? // fill in your type
}
object Model {
implicit def kmeansModel(kmean: Kmeans): Model = new Model {
def setK() = kmeans.setK() // delegate to actual Kmeans
def fit() = kmeans.fit() // delegate to actual Kmeans
}
implicit def bisectingKmeansModel(): Model = ??? // similarly
// usage
val model: Model = if (modelName == "KMeans") {
new KMeans()
} else if (modelName == "BisectKMeans") {
new BisectingKMeans()
} else {
??? // other cases
}
model.setK()
model.fit()
In order to invoke methods .setK() and .fit(), the compiler has to "know" that the variable model is of a specific type that has those methods. You're trying to say, "the variable might be this type or it might be that type but they both have these methods so it's okay."
The compiler doesn't see it that way. It says, "if it might be A and it might be B then it must be the LUB (least upper bound), i.e. the nearest type they both inherit from."
Here's one way to achieve what you're after.
class KMeans { //parent type
def setK(): Unit = ???
def fit(): Unit = ???
}
class BisectingKMeans extends KMeans {
override def setK(): Unit = ???
override def fit(): Unit = ???
}
val model =
if (modelName == "KMeans")
new KMeans()
else //always end with "else", never "else if"
new BisectingKMeans()
model.setK()
model.fit()
Related
I'm trying to test an Object.method which contains some nested methods from a Trait apart of some calculations. These nested methods have to be mocked (they access to a DB so I want to mock their responses).
When I call the real Object.method, it should skip the nested methods call and retrieve what I want. I've tried mocking them but test is still calling them.
Here's my example source code:
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyObject extends MyTrait {
def myParentMethod(a:String) = {
val b = myMethodToMock(a)
val c = a + b
c
}
}
Then in my test:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(a)).thenReturn(b)
//Then I call the parent method:
assert(MyObject.myParentMethod(a) equals c)
It throws a NullPointerException as it's still accessing to myMethodToMock
Your code does not compile, so I am going to guess some things of what you are actually trying to do here ...
You are stubbing a method on a mock, and then calling it on a completely unrelated instance. No wonder it does not work.
A good rule of thumb (and the best practice) is to never mock classes you are actually testing. Split everything you want to mock and test separately into a separate class. This is also known as single responsibility principle (each component should be responsible for a single thing).
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyTrait extends MyTrait {
def myMethodtoMock(a: String) = ???
}
class MyObject(helper: MyTrait = MyTrait) {
def myParentMethod(a: String) = a + helper.myMethodToMock(a)
}
object MyObject extends MyObject()
Now, you can write your test like this:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(any)).thenReturn("b")
new MyObject(myTraitMock).myParentMethod("a") shouldBe "ab"
verify(myTraitMock).myMethodToMock("a")
The main difference here is that you are passing your mock into the object's constructor, so that when it calls the method, it will be the one you stubbed, not the implementation provided by the default class.
You should use composition rather than inheritance, so you can inject an instance of MyTrait that can be a mock or the real one
I have to create a file loader object and I would like the file to be loaded only once at object creation.
What I did until now is create a trait with a method read that will read file and output a list of String.
trait Loader {
protected val readSource: List[String] = {
Source
.fromInputStream(getClass.getResourceAsStream("filename"), "UTF-8")
.getLines()
.toList
}
def transform(delimeter: String): Vector[C] = {
val lines = readSource
// process the lines
}
}
The trait is implemented by several object, and the transform method can be called multiple times in the client code.
I would like to avoid re reading the file each time the transform method is called and my first solution was to extract the val lines = readSource from the transform method and make a function of it def loadFile = readSource and to create a apply method in my objects to call loadFile like so :
object MyLoader extends Loader {
def apply: List[String] = {
loadFile
}
}
I am wondering if this is the right way to do it. Thank you for your advices.
If you want the resource read once for all, then you should do that in a singleton object, which will be initialized once lazily.
Clients should use that object. "Prefer composition over inheritance" is the mantra.
If you want a mix-in that makes it easy to use the object, you can use "self-types" to constrain clients:
trait HasResource { val resource: R = TheResource }
trait Client { self: HasResource => def getR: R = resource }
This is the "cake pattern" way of making stuff available.
I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.
New to scala and trying to get the hang of the class system. Here's a simple set up:
sealed trait Shape{
def sides:Int
}
final case class Square() extends Shape {
def sides() = 4
}
final case class Triangle() extends Shape {
def sides() = 3
}
Now, I want to create a function that takes anything of type shape, which we know will have a sides() method implemented, and make use of that method.
def someFunction(a: Shape)={
val aShape = a()
aShape.sides()
}
But this hits an error at val aShape = a(), as there's no type a.
I realize that in this example, it's excessive to create someFunction, since sides() can be accessed directly from the objects. But my primary question is in the context of someFunction - I'd like to pass a class to a function, and instantiate an object of that class and then do something with that object. Thanks for your help.
What are you trying to do with that line of code? You already have a shape, the one passed in called a. Just remove that line and call a.sides().
Stylistically, there are several problems. First of all, class names should start with a capital letter. Second, sides seems like an immutable property, not a mutating method, so it should be declared and overridden with no parentheses. You also need override modifiers in your subclass. Last, you can do without the empty braces: {4} should just be 4.
There is several methods to do this. One is a complex one using reflection, second is little bit simplier, using a builder and third is most straightforward for your use case.
Just change definition of someFunction to
def someFunction(a: ()=>Shape)={
val aShape = a()
aShape.sides
}
so someFunction(Square) return 4 and someFunction(Triangle) returns 3 . Note this work only with case classes because real thing, we are passing here is not class itself, but it's auto-generated companion object
But more often there no need to define classes, you could write inside any context except top level thing just like
def square() = new Shape{
def sides() = 4
}
def triangle() = new Shape{
def sides() = 3
}
Next thing: methods with empty parameter list are generally reading as method that have side effects. So it is more convenient to define your type like
sealed trait Shape{
def sides:Int
}
and if you define your builders like
def square = new Shape{
def sides = 4
}
def triangle = new Shape{
def sides = 3
}
you should use them as someFunction(square _) telling, that you gonna use method call and not the value it's returning
And last thing is: if you really need the code, that creates some object, but it could contain complex computations, resource handling or some probable exception, so you want to hold over it's execution until it' really needed, you could use call-by-name parameters which is equivalent to R , which i assume you are familiar with
Unless shape has an apply function, you cannot call () on a shape object.
If you want to assign aShape to a, simply write val aShape = a.
But since I do not see the added value, you might as well call the sides function directly on a:
def someFunction(a:shape) = {
val sides = a.sides
// use sides
}
This is the closest translation for what you wrote:
sealed trait Shape {
def sides: Int
}
case object Square extends Shape {
override val sides = 4
}
case object Triangle extends Shape {
override val sides = 3
}
def someFunction(a: Shape) =
val shapeSides = a.sides
Some notes:
Classes in scala should be CamelCase
Your subclasses have no instance members, so you can use a singleton object
You if you have a: Shape it means that a is a Shape, and you haven't defined anything that would let you call () on it.
You can omit braces when there's only one expression inside
You can override a def with val if it's static
I have some functions that access a database, which I need to mock for testing purposes.
For ease of use, I would like to define these functions within another function, where I can leverage scope to reduce the number of arguments I have to pass.
I need to test the parent function, while mocking the nested functions.
Are there any tricks to mock functions that are nested?
As a secondary question, are there ways to mock functions when nested at arbitrary depth?
And a side note: my project is light enough I'm not even using classical mocking, just stackable traits like this blog post suggests; but for this question, any kind of mocking is fine.
Here is some very simple example code:
class Storage {
def storeData(specId: Long, data: String): Unit = {
val rawPath = "/path/to/file"
def storeFsEntry: Unit = {
// do stuff
}
def storeDbEntry: Unit = {
// do stuff we need mocked
}
if ( specId == 1 )
{
storeDbEntry
storeFsEntry
}
}
}
It's not possible, but you can define a trait and implement it inside your function (if you really want this logic been implemented inside):
class Storage {
trait Storing {
def path: String //you have to define all free members
def storeDbEntry: Unit
def storeFsEntry: Unit
}
def storeData(specId: Long, data: String, storingDefault: Option[Storing] = None): Unit = {
val myStoring = new Storing {
...implement it here
}
val storing = storingDefault getOrElse myStoring
import storing._
if ( specId == 1 ) {
storeDbEntry
storeFsEntry
}
}
}
Your mock will be something like that:
trait StorageMock extends Storage {
override def storeData(specId: Long, data: String, storingDefault: Option[Storing] = None): Unit = {
val storingOverride = new Storing { ... } //mocking functionality
super.storeData(specId, data, storingDefault orElse Some(storingOverride))
}
}
new Storage with StorageMock
You may also turn storingDefault into a member instead of function parameter.
The reason why it's not possible to do same for inner functions is that they are private and also typecheck can't be performed on them (in comparison with inner traits).