Dependency injection without classes Scala

Viewed 138

I like to write Scala code without classes, using just functions and objects.

e.g.

object Something {
  def foo() = {
    SomeDependency().doIt()
    ...
  }
}

object SomethingElse {
  def baz = {
    val x = Something.foo()
    ...
  }
}

However, I run into the issue that I can't test that code, since I can't mock anything out. I'd have to refactor the code and make it take a parameter and then have to needlessly instantiate classes.

class Something(someDependency: SomeDependency) {
  def foo() = {
    someDependency.doIt()
    ...
  }
}

class SomethingElse(something: Something) {
  def baz = {
    val s = new SomeDependency()
    val x = new Something(s).foo()
    ...
  }
}

What I sometimes do is use implicits but it gets cumbersome since you need to add it to every method.

object Something {
  def foo()(implicit someDependency: SomeDependency) = {
    someDependency().doIt()
    ...
  }
}

object SomethingElse {
  def baz(implicit something: Something) = {
    val x = something.foo()
    ...
  }
}

In other languages like Python/JS, you can just mock the dependency directly, instead of making your class take in dependencies. Is there any way to solve this, or is just an antipattern to write scala without classes.

1 Answers

Despite being able to work imperatively in Scala, Scala is designed for Functional Programming. The fact that you need to mock things means that your functions have side effects, therefore, they are not pure functions so it isn't functional programming.

There are mock frameworks in Scala but they don't allow you to overwrite the functionality of your functions like you can do with Python, for example.

You could use also high order functions to pass dependencies, something like this:

object Something {
  def foo(someDependencyFunction: A => B): C = {
    someDependencyFunction(...)
    ...
  }
}

object SomethingElse {
  def bar(SomethingFoo: (A => B) => C)(someDependencyFunction: A => B): D = {
    SomethingFoo(someDependencyFunction)
      ...
  }
}

But I don't really see the point of avoiding classes, maybe if you explain why you don't want to use classes someone can help better on a solution

Related