I have a simple trait
trait SomeTrait {
val sourceData: SourceData
}
SourceData class has constructor parameter p: Array[String].
Now, when I extend this trait in Object, we must provide implementation for sourceData.
object SomeObject extends SomeTrait {
override val sourceData: SourceData = ???
def main(sysArgs: Array[String]){...}
}
But what if class SourceData needs sysArgs from main method, how can I override sourceData in main method, not in body of SomeObject. Something like this:
object SomeObject extends SomeTrait {
def main(sysArgs: Array[String]){
override val sourceData: SourceData = new SourceData(sysArgs)
}
}
I do not want to use var, as val immutability is preferred. And also I want to have trait with no implementation in order to force all sub classes to implement sourceData. What other solution I have for this?
You can't avoid mutability in this situation. sourceData must have a value before main is called, and main must be able to change that value, so the value must be mutable.
One option is to make sourceData a def (which is a good idea anyway) and have it access a private var in SomeObject:
trait SomeTrait {
def sourceData: SourceData
}
object SomeObject extends SomeTrait {
private var mySource: SourceData = ???
def sourceData = mySource
def main(sysArgs: Array[String]) = {
mySource = new SourceData(sysArgs)
}
}
The root problem here is having a top-level object that needs run-time initialisation. This is required because SomeObject is a top-level object that is accessed directly from other parts of the code.
The solution to this is dependency injection rather than a global object.
trait SomeTrait {
def sourceData: SourceData
}
object SomeObject {
case class SomeData(sourceData: SourceData) extends SomeTrait
def main(sysArgs: Array[String]) = {
val theSource = SomeData(SourceData(sysArgs))
// Pass this instance to the rest of the code that needs it
restOfTheProgram(theSource)
}
}
The rest of the code uses the instance of SomeTrait that is passed to it rather than using SomeObject directly.
There is no way to do that in Scala. You need to have a class inherit SomeTrait and instantiate it from the main method.
Related
I'd like to create an abstract class, and be able to add members to it that reference attributes of the implementing class's companion object. Something like this (Scala pseudocode):
abstract class Fruit(cultivar: String) {
// How do I reference the implementing class's companion object here?
def isTastyCultivar(): Boolean = Fruit.tastyCultivars.contains(cultivar)
}
// how do I implement what I am thinking of as "the abstract companion object"
abstract object Fruit {
val tastyCultivars: Set[String] // must be implemented
// by the concrete object
}
class Apple(cultivar: String) extends Fruit(cultivar) {
}
object Apple extends Fruit{ // presumably this is not correct;
// it needs to extend the FruitObject
// or whatever it is
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
class Tomato(cultivar: String) extends Fruit(cultivar) {
}
object Tomato extends Fruit{
val tastyCultivars = Set("Roma")
}
val a1 = new Apple("Red Delicious")
val a2 = new Apple("Honeycrisp")
a1.isTastyCultivar() // should return true
a2.isTastyCultivar() // should return false
val t1 = new Tomato("Roma")
val t2 = new Tomato("San Marzano")
t1.isTastyCultivar() // should return true
t2.isTastyCultivar() // should return false
Sorry if this is a dumb question, or if asked previously (I'm not confident in how to word this question so I couldn't easily search for it). Thanks in advance!
One possible solution is to use the type class pattern. We have our domain model (or algebra) via ADTs:
sealed trait Fruit
case class Apple() extends Fruit
case class Orange() extends Fruit
We have our type class, which defines the structure we want to supply:
trait TastyCultivarSupplier[T <: Fruit] {
def tastyCultivars: Set[String]
}
And now each type which has tasty cultivars will need to implement the type class in order to provide them. One possible way to do this is to implement the typeclass inside the companion object:
object Apple {
implicit def appleTastyCultivars = new TastyCultivarSupplier[Apple] {
override def tastyCultivars: Set[String] = Set("Yummy stuff")
}
}
Inside the consumer, or the type which wants to get the tasty cultivars, we require an implicit evidence of a TastyCultivarSupplier:
class TastyCultivarConsumer {
def isTasty[T: TastyCultivarSupplier](name: String): Boolean =
implicitly[TastyCultivarSupplier[T]].tastyCultivars.contains(name)
}
When isTasty is invoked, it will need to have one of the suppliers in scope, otherwise a compile time error will occur:
def main(args: Array[String]): Unit = {
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
}
Will give us:
Error:(33, 48) could not find implicit value for evidence parameter
of type TastyCultivarSupplier[T]
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
To fix this, we import the supplier we want:
def main(args: Array[String]): Unit = {
import Apple._
println(new TastyCultivarConsumer().isTasty("Yummy stuff"))
}
And now our code compiles. Note that the implementer isn't forced to write the evidence inside the companion object, he is free to do so anywhere he wants, as long as it's in scope for the compiler to find.
A simple solution (the one Scala Collections use): just add a method returning the companion to the class.
trait FruitCompanion {
val tastyCultivars: Set[String]
}
abstract class Fruit(cultivar: String) {
def companion: FruitCompanion
def isTastyCultivar(): Boolean = companion.tastyCultivars.contains(cultivar)
}
class Apple(cultivar: String) extends Fruit(cultivar) {
def companion = Apple
}
object Apple extends FruitCompanion {
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
Note that you can't enforce that the companion actually returns the companion object, but you don't really need it.
It is not possible to do what you are asking.
You are asking about overriding members of object. objects in scala are equivalent of static classes in Java with all members being static.
Companion object with its class would be a class with both static and none static members in Java.
You can't override them. You can't do it in Java and you can't do it in Scala.
Alternative solution:
Just define tastyCultivars in class.
abstract class Fruit(cultivar: String) {
val tastyCultivars: Set[String]
def isTastyCultivar(): Boolean = tastyCultivars.contains(cultivar)
}
class Apple(cultivar: String) extends Fruit(cultivar) {
val tastyCultivars: Set[String] = Set("Red Delicious", "Granny Smith")
}
class Tomato(cultivar: String) extends Fruit(cultivar) {
val tastyCultivars = Set("Roma")
}
val a1 = new Apple("Red Delicious")
val a2 = new Apple("Honeycrisp")
println("Should return true, is " + a1.isTastyCultivar())
println("Should return false, is " +a2.isTastyCultivar())
val t1 = new Tomato("Roma")
val t2 = new Tomato("San Marzano")
println("Should return true, is " +t1.isTastyCultivar())
println("Should return false, is " +t2.isTastyCultivar())
Output:
$ scala fruit.scala
Should return true, is true
Should return false, is false
Should return true, is true
Should return false, is false
Many thanks to Yuval for teaching me about typeclasses; I have written a solution using his technique which satisfies all my original criteria:
// Fruit instance members
abstract class FruitClass(cultivar: String) {
def getCultivar: String = cultivar
}
// Obviously not really an object but serves the purpose of
// the thing I envisioned as the "abstract object" which is not a thing
// I.e., a place to put fruit static members
trait FruitObject[A <: FruitClass] {
// Any subclass of fruit must (statically) specify their set of tasty cultivars...
val tastyCultivars: Set[String]
// ...but they can inherit the common implementation of isTastyCultivar()
def isTastyCultivar(x: A): Boolean = tastyCultivars contains x.getCultivar
}
// Subclass #1: Apples
class Apple(cultivar: String) extends FruitClass(cultivar)
implicit object AppleIsFruit extends FruitObject[Apple] {
val tastyCultivars = Set("Red Delicious", "Granny Smith")
}
// Subclass #2: Tomatoes
class Tomato(cultivar: String) extends FruitClass(cultivar)
implicit object TomatoIsFruit extends FruitObject[Tomato] {
val tastyCultivars = Set("Roma")
}
def isTastyCultivar[A <: FruitClass: FruitObject](thing: A) =
implicitly[FruitObject[A]].isTastyCultivar(thing)
isTastyCultivar(new Apple("Red Delicious")) // true
isTastyCultivar(new Apple("Honeycrisp")) // false
isTastyCultivar(new Tomato("Roma")) // true
isTastyCultivar(new Tomato("San Marzano")) // false
Gustek is quite right that object members cannot be overridden but this method seems to achieve the same effect without actually using a companion object for Fruit to declare static members.
I have a package foo which contains class FStream. The package object of foo defines a few implicit value classes that provide extender methods for FStream. I would like to move these value classes out of the package object and into their own individual files, but I also want them to always be available when I use FStream (or preferably, when I use anything from foo package. Is it possible to accomplish this? I tried putting implicit value classes into other objects, but I can't extend from objects. Tried putting them in classes or traits, but implicit value classes can only be defined in other objects.
foo/FStream.scala
package foo
class FStream {
def makeFoo(): Unit = ???
}
foo/package.scala
package foo
package object foo {
// I want to move these definitions into separate files:
implicit class SuperFoo(val stream: FStream) extends AnyVal {
def makeSuperFoo(): Unit = ???
}
implicit class HyperFoo(val stream: FStream) extends AnyVal {
def makeHyperFoo(): Unit = ???
}
}
bar/usage.scala
package bar
import foo._ // something nice and short that doesn't reference individual value classes
val x: FStream = ???
x.makeSuperFoo() // should work
x.makeHyperFoo() // should work
I recommend you to read the mandatory tutorial first.
My solution is to use FStream's companion object. So you can just import FStream and get all the functionality. This also uses trait to separate files.
foo/FStream.scala
package foo
class FStream {
def makeFoo(): Unit = ???
}
// companion provides implicit
object FStream extends FStreamOp
foo/FStreamOp.scala
package foo
// value class may not be a member of another class
class SuperFoo(val stream: FStream) extends AnyVal {
def makeSuperFoo(): Unit = ???
}
class HyperFoo(val stream: FStream) extends AnyVal {
def makeHyperFoo(): Unit = ???
}
trait FStreamOp {
// you need to provide separate implicit conversion
implicit def makeSuper(stream: FStream) = new SuperFoo(stream)
implicit def makeHyper(stream: FStream) = new HyperFoo(stream)
}
usage.scala
import foo.FStream
object Main {
def main(args: Array[String]): Unit = {
val x: FStream = ???
x.makeSuperFoo() // should work
x.makeHyperFoo() // should work
}
}
In the following (simplified) example, how can I stub the value of a trait that inherits fields from a class with scalamock?
trait MyTrait extends MyClass
class MyClass(val location: Location)
val expectedValue = ???
val dor: MyTrait = stub[MyTrait]
(dor.location.continuousFeatureValues).returns(expectedValue)
'location' is the parameter of MyClass or a data member of MyClass? Is it OK to change MyClass as:
class MyClass() {
val location: Location = new Location
}
If it is OK, you can override the location as a workaround:
//source code
class Location {
def continuousFeatureValues: String = "location"
}
class MyClass() {
val location: Location = new Location
}
class MyTrait extends MyClass
// test code
it should "mock" in {
val loc = mock[Location]
val dor: MyTrait = new MyTrait {override val location = loc}
(loc.continuousFeatureValues _).expects().returning("good")
dor.location.continuousFeatureValues shouldBe ("good")
}
I would refactor that code, as it is a bit of a dead end with a trait extending a class with a non-default constructor.
If you were to mock that class directly, you still could not define actions on location as it is a val, and those are immutable in Scala. Make it a def on MyTrait and have MyClass extend MyTrait and your design should be simpler to work with (and mock).
I have a trait and an object inherited from this trait:
trait MyTrait {
def method1(a: Int)
}
object MyObject extends MyTrait {
def method1(a: Int) = //....
}
Assuming I have only the full name of an object as a string (namespace + its name) and knowing it's inherited from MyTrait, how do I
create it at runtime
call its method method1
return it to a calling code so that other clients can use it?
I read about reflection in Scala, but, oddly enough, almost all I found was about creating a class at runtime.
UPDATE:
I wonder, why doesn't this work:
scala> object MyObject { def method1(a: Int) = 123456 }
defined module MyObject
scala> val cs = Class.forName("MyObject")
java.lang.ClassNotFoundException: MyObject
due to the error java.lang.ClassNotFoundException: MyObject
If you want to get an instance of a singleton scala object via reflection, you can try this:
package code
object ReflectTest extends App{
val clazz = Class.forName("code.MyObject$")
val myObj = clazz.getField("MODULE$").get(classOf[MyTrait]).asInstanceOf[MyTrait]
println(myObj.method1(2))
}
trait MyTrait {
def method1(a: Int):Int
}
object MyObject extends MyTrait {
def method1(a: Int) = a + 1
}
Now I'm not a big fan of obtaining instances of scala objects via reflection (seems kinds silly given that it's a singleton) but maybe you have a valid use case for this.
Given a trait MyTrait:
trait MyTrait {
def doSomething = println("boo")
}
it can be mixed into a class with extends or with:
class MyClass extends MyTrait
It can also be mixed upon instantiating a new instance:
var o = new MyOtherClass with MyTrait
o.doSomething
But...can the trait (or any other if that makes a difference) be added to an existing instance?
I'm loading objects using JPA in Java and I'd like to add some functionality to them using traits. Is it possible at all?
I'd like to be able to mix in a trait as follows:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
I have a idea for this usage:
//if I had a class like this
final class Test {
def f = println("foo")
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}
you can use this trait as below:
import MyTrait._
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
for your example code:
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
I hope this can help you.
UPDATED
object AnyTrait {
implicit def innerObj[T](o: MixTest[T]):T = o.obj
def ::[T](o: T) = new MixTest(o)
final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}
but this pattern has some restrict, you can't use some implicit helper method that defined already.
val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern) // you can invoke String's method
println(c.format("MyTrait")) //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1
An existing runtime object in the JVM has a certain size on the heap. Adding a trait to it would mean altering its size on the heap, and changing its signature.
So the only way to go would be to do some kind of transformation at compile time.
Mixin composition in Scala occurs at compile time. What compiler could potentially do is create a wrapper B around an existing object A with the same type that simply forwards all calls to the existing object A, and then mix in a trait T to B. This, however, is not implemented. It is questionable when this would be possible, since the object A could be an instance of a final class, which cannot be extended.
In summary, mixin composition is not possible on existing object instances.
UPDATED:
Related to the smart solution proposed by Googol Shan, and generalizing it to work with any trait, this is as far as I got. The idea is to extract the common mixin functionality in the DynamicMixinCompanion trait. The client should then create a companion object extending DynamicMixinCompanion for each trait he wants to have the dynamic mixin functionality for. This companion object requires defining the anonymous trait object gets created (::).
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
trait OtherTrait {
def traitOperation = println("any trait")
}
object OtherTrait extends DynamicMixinCompanion[OtherTrait] {
def ::[T](o: T) = new Mixin(o) with OtherTrait
}
object Main {
def main(args: Array[String]) {
val a = "some string"
val m = a :: OtherTrait
m.traitOperation
println(m.length)
}
}
I usually used a implicit to mix in a new method to an existing object.
See, if I have some code as below:
final class Test {
def f = "Just a Test"
...some other method
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object HelperObject {
implicit def innerObj(o:MixTest) = o.obj
def mixWith(o:Test) = new MixTest(o)
final class MixTest private[HelperObject](obj:Test) extends MyTrait
}
and then you can use MyTrait method with an already existing object Test.
val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething
in your example, you can use like this:
import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething
I am thinking out a prefect syntax to define this HelperObject:
trait MyTrait {
..some method
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
What about an implicit class? It seems easier to me compared to the way in the other answers with a final inner class and a "mixin"-function.
trait MyTrait {
def traitFunction = println("trait function executed")
}
class MyClass {
/**
* This inner class must be in scope wherever an instance of MyClass
* should be used as an instance of MyTrait. Depending on where you place
* and use the implicit class you must import it into scope with
* "import mypackacke.MyImplictClassLocation" or
* "import mypackage.MyImplicitClassLocation._" or no import at all if
* the implicit class is already in scope.
*
* Depending on the visibility and location of use this implicit class an
* be placed inside the trait to mixin, inside the instances class,
* inside the instances class' companion object or somewhere where you
* use or call the class' instance with as the trait. Probably the
* implicit class can even reside inside a package object. It also can be
* declared private to reduce visibility. It all depends on the structure
* of your API.
*/
implicit class MyImplicitClass(instance: MyClass) extends MyTrait
/**
* Usage
*/
new MyClass().traitFunction
}
Why not use Scala's extend my library pattern?
https://alvinalexander.com/scala/scala-2.10-implicit-class-example
I'm not sure what the return value is of:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
but let us say, it is DBEntity for our example. You can take the class DBEntity and convert it to a class that extends your trait, MyTrait.
Something like:
trait MyTrait {
def doSomething = {
println("boo")
}
}
class MyClass() extends MyTrait
// Have an implicit conversion to MyClass
implicit def dbEntityToMyClass(in: DBEntity): MyClass =
new MyClass()
I believe you could also simplify this by just using an implicit class.
implicit class ConvertDBEntity(in: DBEntity) extends MyTrait
I particularly dislike the accepted answer here, b/c it overloads the :: operator to mix-in a trait.
In Scala, the :: operator is used for sequences, i.e.:
val x = 1 :: 2 :: 3 :: Nil
Using it as a means of inheritance feels, IMHO, a little awkward.