1

I'm implementing some code in Scala, following a tutorial in Java.

The tutorial has a piece of code that can be minimized into the following:

public abstract class A {
    private int id;

    public A(String name) {
        id = Helper.getId(name);
        fetchAllAttributes();
    }

    protected abstract void fetchAllAttributes();

    protected int fetchAttribute(String attribute) {
        Helper.getAttribute(id, attribute);
    }

    public class B extends A {
        int volume;

        public B() {
            super("B");
        }

        @Override
        protected void fetchAllAttributes() {
            volume = super.fetchAttribute("volume");
        }

    }
}

And this is what it looks like when you translate it into Scala:

abstract class A(val name: String) {
  private val id = Helper.getId(name)
  fetchAllAttributes()

  protected def fetchAllAttributes(): Unit

  protected def fetchAttribute(attribute: String): Int = {
    Helper.getAttribute(id, attribute)
  }

  class B() extends A("B") {
    var volume = 0

    override protected def fetchAllAttributes(): Unit = {
      volume = super.fetchAttribute("volume")
    }
  }

}

And here I'd like to ask two questions:

  1. Is there a name for this pattern, where you call an abstract method in the abstract class' constructor and provide a method for the child classes to use in their implementation?
  2. As a Scala developer, I really don't like mutable objects and variables. Is there a good way to implement this in an immutable fashion, using only vals?
summerbulb
  • 5,709
  • 8
  • 37
  • 83
  • There is no universal way to translate any mutable code into immutable. You need to explain what problem mutable code solves then people will be able to help find immutable approach to solve it. – Nazarii Bardiuk May 15 '18 at 18:44
  • 1
    Calling an overridable method (much less an abstract method) from a base class constructor is an anti-pattern in Java. The subclass's method will be executing before the subclass constructor executes, potentially resulting in all sorts of problems. For more information, see [this thread](https://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors). The right way to deal with this is to not expose any public constructors and instead define a factory method that will call the object's `fetchAllAttributes()` method after the object is fully constructed. – Ted Hopp May 15 '18 at 18:48

2 Answers2

2
  1. You can call it an anti-pattern. See previous discussions on SO about calling overridable methods from a constructor.
  2. When refactoring java code to scala code then what helped me the most in the beginning was understanding what are methods with side effects. You don't want to have methods in classes that depend on mutable fields and/or change them. (Like your class B has with that volume) This small principle helps keep the classes clear from mutable state. This is not a rule which is set to stone though. With akka actors it is not uncommon to have mutable state for example.

A quote from scala tutorial (Source):

Again, this means that a function should not have any side effects. It should take input variables, not modify those variables, then calculate and return something new. Unlike object-oriented programming, you should not change (mutate) the state of other variables, even if those variables are (a) variables of your class or (b) variables that were passed in to your function/method.

Miko
  • 135
  • 7
0

I don't know of a name for this pattern. It's hard to know exactly how to translate it into immutable style without knowing the goal of the pattern, but here's something similar, if you squint hard enough:

class FactoryFromAttributes[A](name: String) {
  def construct(f: (String => Int) => A): A = {
    val id = Helper.getId(name)
    f(str => Helper.getAttribute(id, str))
  }
}

class B(volume: Int)

object B extends FactoryFromAttributes[B]("B") {
  def apply(): B = construct { fetchAttribute =>
    new B(fetchAttribute("volume"))
  }
}

To me, this kind of logic makes more sense in a companion object, so I moved it to there, rather than keep an odd subclass relationship in the resulting constructed class. Initialization logic outside of constructors rarely lends itself to good immutable style.

Joe K
  • 18,204
  • 2
  • 36
  • 58