I have two packages in Scala: package foo and package bar. Both have a Utils object in them that has same methods doSomething() and doSomethingElse(). Code looks like this:
Inside package foo
object Utils{
def doSomething()
def doSomethingElse()
}
Inside package bar
object Utils{
def doSomething()
def doSomethingElse()
}
Is there a way I can provide a common ground from where both the packages can use the methods in Utils object? I want to avoid code duplication. What I have in mind is to write a package object in one of the packages and import that in the other package. But is there a better way to eliminate code duplication?
package objects can inherit from other traits, abstract classes and classes, just like any other object. Simply provide the methods in an appropriately named trait and include it in both:
trait SomethingHandler {
def doSomething() = ???
def doSomethingElse() = ???
}
package object foo extends SomethingHandler
package object bar extends SomethingHandler
Alternatively, you can use an object and import it into both package namespaces:
object SomethingHandler {
def doSomething() = ???
def doSomethingElse() = ???
}
package object foo {
import some.package.SomethingHandler._
}
package object bar {
import some.package.SomethingHandler._
}
Place the Utils object in a separate package util and import it where you use it?
Or else alias it in your package objects:
package object foo {
val Utils = util.Utils
}
If they don't have all their methods in common, factor out common methods in a trait:
trait Common {
def doSomething() = ???
def doSomethingElse() = ???
}
object Utils extends Common {
...
}
Related
The following fails to compile on the last line:
// importing implicit class thru two levels
object Foo {
implicit class IntWithSquare(x: Int) {
def square = x*x
}
}
object Bar {
import Foo._
println(4.square) // this works
}
import Bar._
println(5.square) // this fails to compile
How can we force the export of imported implicit class from within Bar? The motivation for this is to keep object Foo neat by defining all implicits in a separate file. Same problem exists for other definitions coming from Foo into Bar. But, a simple re-definition of the top names works in such cases:
// importing regular definitions and types thru two levels
object Foo {
def someBigFunc(): Int = {
42
}
type Word = String
}
object Bar {
import Foo._
val someBigFunc = Foo.someBigFunc _
type Word = Foo.Word
}
import Bar._
someBigFunc()
val w: Word = "word"
The approach used to do what you want to achieve is usually to define traits and have an object extending all wanted traits.
trait Foo {
// Define implicit stuff here
}
trait Fii {
// Define other implicits here
}
object Bar extends Foo with Fii
import Bar._ // will provide the implicits from Foo and Fii
I want to extend a trait from Scala object and override those methods which are in trait. So my doubt is those methods will become static to that Object
or instance methods, and is this good approach to extend from trait to Scala Object. Please help on this
trait A{
def show:Unit
}
object B extends A{
override def show(): Unit = {
println("inside Object")
}
}
There are no static methods in Scala. object can indeed extend a trait. Overriden methods, like show, do not become static methods, instead they belong to a single instance of B.type. This is the singleton pattern provided by Scala's object definition facility.
Try the following in Scala REPL:
object B
B
It should output something like
res0: B.type = B$#5688722f
Note how the value B has type B.type, so B is just a value/instance, nothing to do with statics.
Hm, I think a common example/usecase of what you've just described is extending the App trait and overriding the main definition.
object test extends App
{
override def main (args: Array[String]): Unit = {
println("Hello, let's get started")
}
}
In general though, why don't you define the class itself to extend the trait?
If you are going to instantiate new instances of B using B() (instead of new B()) it makes sense to do this.
trait A{
def show:Unit
}
object B { // companion aka singleton object
def apply(){
...
}
}
class B extends A{
override def show(): Unit = {
println("inside Object")
}
}
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
}
}
I just found the type class concept of Scala and like it actually very much. The problem I have it that all examples I found put the type classes (objects) under one object (Like here: http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html)
Maybe this is wrong but I am a friend of having one file per class. So what I like to do is to put the type classes into several files which would mean that each implementation needs to be put into a seperate object. This now leads to the "problem" that I need to import every single implementation manually. To clarify better here a small example:
package sth
import sth.like.Like
import sth.like.StringLike._
import sth.like.IntLike._
object Application extends App {
def t[T](arg: T)(implicit l: Like[T]) = {
l.print(arg)
}
t(1)
t("Blub")
}
-
package sth.like
trait Like[T] {
def print(arg: T)
}
-
package sth.like
object IntLike {
implicit object LikeIntLike extends Like[Int] {
def print(arg: Int): Unit = println(s"INT $arg")
}
}
-
package sth.like
object StringLike {
implicit object LikeStringLike extends Like[String] {
override def print(arg: String): Unit = println(s"STRING: $arg")
}
}
This works so far. I know, the wildcard import in Application is not necessary but that is not the point. As you can see I need to import both StringLike and IntLike in Application because otherwise these are not available for the Application object.
So is it possible to do this in a generic way or is it completely bad practise to do it this way?
You could put your implicits inside traits, not objects
trait IntLike {
implicit object LikeIntLike extends Like[Int] {
def print(arg: Int): Unit = println(s"INT $arg")
}
}
And then have object with the same name, extending this trait, which would give you what you had earlier, you can import each implicit individually.
object IntLike extends IntLike
You can do the same for all other instances of your typeclass:
trait StringLike {
implicit object LikeStringLike extends Like[String] {
override def print(arg: String): Unit = println(s"STRING: $arg")
}
}
object StringLike extends StringLike
And in another file, you can combine all traits together like this:
object Implicits extends StringLike with IntLike
and import just the Implicits object if you want all your implicits in scope.
package sth
import sth.like.Like
import sth.like.Implicits._
object Application extends App {
def t[T](arg: T)(implicit l: Like[T]) = {
l.print(arg)
}
t(1)
t("Blub")
}
Optionally, you can mixin traits you need
object Application extends App with StringLike with IntLike { ... }
or even do
trait Implicits extends StringLike with IntLike
object Implicits extends Implicits
object Application extends App with Implicits { ... }
thank you very much for your answer. But I also would need to add new type classes manually to the Implicits, wouldn't I?
Couldn't I use then package objects for simplicity reasons like here:
http://naildrivin5.com/scalatour/wiki_pages/PackageObjects/
?
I mean this part:
package opower {
package object controller {
type Secured = org.springframework.security.access.annotation.Secured
type Controller = org.springframework.stereotype.Controller
...
}
}
Since it seems that there is no dynamic way I could just put all type classes into the controller object and could this then import.
Or do I missunderstand the package object?
I'm trying to provide different sets of implementations for a list of type classes, where importing different package objects would give the end user a different version of a TypeClass implementation into scope, with the swap being completely invisible.
trait TypeClass[T] {
def name: String
}
trait DefaultTypeClasses {
implicit val String: TypeClass[String]
implicit val Int: TypeClass[Int]
}
trait FirstImplementor extends DefaultTypeClasses {
implicit object String extends TypeClass[String] {
def name = "test"
}
implicit object Int extends TypeClass[Int] {
def name = "int"
}
}
object FirstImplementor extends FirstImplementor
object Test {
import FirstImplementor._
def doSomething[T : TypeClass](value: T): Unit = {
println(implicitly[TypeClass[T]].name)
}
doSomething("test")
}
The above works as expected, but if do:
trait DefaultDefinitions extends DefaultTypeClasses {
}
package object something extends DefaultDefinitions with FirstImplementor {}
And then I import the same package object into the scope of the Test object, like this:
import com.blabla.something._ // should bring all type class definitions from FirstImplementor into scope.
object Test {
def doSomething[T : TypeClass](value: T): Unit = {
println(implicitly[TypeClass[T]].name)
}
doSomething("test")// Cannot find implicit value for TypeClass[String]
doSomething[String]("test")(String) // if passed explicitly it compiles as expected, no more imports necessary.
}
For whatever reason, the materialised type class is available in explicit scope by name, but not in implicit scope. Sounds like my knowledge of the SLS is experiencing a gap, could anyone please clarify?
But if you create Implicits object in package, it works fine. However I have no idea if original error is a bug in scalac or correct behavior
package object something {
object Implicits extends DefaultDefinitions with FirstImplementor
}
import something.Implicits._