Total Scala Noob trying to do something that's easy in Java

#1

I’m trying to do something similar to KeepLast in Scala, but I don’t seem to be able to figure out a way to do generic types. I don’t know where to even begin. I’ve been trying to teach myself Scala now for 3 days and have been googling constantly trying to figure this out.

/**

  • Class I’m trying to figure out how to do in Scala

  • @author Michael

  • @param
    */
    public class KeepLast {
    private T value;
    private T lastValue;

    public KeepLast(T value) {
    this.value = value;
    }

    public void setValue(T newValue) {
    lastValue = value;
    value = newValue;
    }

    public T getValue() { return value; }

    public T getLastValue() { return lastValue; }
    }

/**

  • Simple example of use
  • @author Michael

*/
public class MultipleTypesTest {

private KeepLast<Integer> keepInteger;
private KeepLast<String> keepString;
private KeepLast<Boolean> keepBool;

public MultipleTypesTest() {
	keepInteger = new KeepLast<Integer>(0);
	keepString = new KeepLast<String>("not initialized");
	keepBool = new KeepLast<Boolean>(false);
}
	
public KeepLast<Integer> getKeepInteger() { return keepInteger;	}
public KeepLast<String> getKeepString() { return keepString;	}
public KeepLast<Boolean> getKeepBoolean() { return keepBool;	}


public static void main(String[] args) {
	
	MultipleTypesTest testOb = new MultipleTypesTest();

	System.out.println("" + testOb.getKeepInteger().getValue());
	System.out.println("" + testOb.getKeepString().getValue());
	System.out.println("" + testOb.getKeepBoolean().getValue());
	
	System.out.println();
	testOb.getKeepInteger().setValue(17);
	testOb.getKeepString().setValue("Hello World");
	testOb.getKeepBoolean().setValue(true);
	
	System.out.println("" + testOb.getKeepInteger().getValue());
	System.out.println("" + testOb.getKeepString().getValue());
	System.out.println("" + testOb.getKeepBoolean().getValue());
}

}

#2

I’d appreciate any help anyone can give me.

Thanks in advance

#3

It would help to know what you tried, where you got stuck, and what the error messages or unexpected behavior were at the point where you got stuck.

Regardless,

class KeepLast[T](private var _value: T) {
  private var _lastValue: T = _
  def lastValue = _lastValue
  def value = _value
  def value_=(newValue: T): Unit = {
    _lastValue = _value
    _value = newValue
  }
}

scala 2.12.8> val k = new KeepLast(5)
k: KeepLast[Int] = KeepLast@48ae9e8b

scala 2.12.8> (k.value, k.lastValue)
res4: (Int, Int) = (5,0)

scala 2.12.8> k.value = 6
k.value: Int = 6

scala 2.12.8> (k.value, k.lastValue)
res5: (Int, Int) = (6,5)
#4

Here’s the full thing of what I’m actually trying to do. it’s allowing another class to subscribe to it and process any value changes. Here’s what I’m at right now. still getting errors I don’t understand (in comments), but hopefully I’m farther along and not going down the wrong road:

trait ObserverTrait[S] {
  this: S =>
  private var observers: List[S => Unit] = Nil
  def addObserver(observer: S => Unit) = observers = observer :: observers
  def notifyObservers() = observers.foreach(_.apply(this))
}

/**
  * Class to hold a value and the last value set
  * @param _value the value to set. can be any type
  * @tparam T
  */
abstract class PropertyBase[T](private var _value: T) {
  private var _lastValue: T = _
  def lastValue = _lastValue
  def value = _value
  def updateValues(newValue: T): Unit = {
    _lastValue = _value
    _value = newValue
  }
}

/**
  * Class to take the PropertyBase and add an observer
  * @param _value the value to set. can be any type
  * @tparam T
  */
class Property[T](private var _value: T) extends PropertyBase()
  with ObserverTrait[PropertyBase] { // <- gives error message: "Type PropertyBase takes
                                     // type parameters" but I don't know what that means
  override def setValue2(newValue: T): Unit = {
    updateValues(newValue) // <- gives error message "Type mismatch, expected: Nothing, actual: T"
                           // but I don't understand why it's expecting Nothing
    notifyObservers()
  }
}

class ChangeProcessor {
  def receiveUpdate(account: PropertyBase) =  // <- gives error message: "Type PropertyBase takes
                                                   // type parameters" but I don't know what that means
    println("Value change: " + account.value.toString)
}

object Main extends App {
  val ar = new ChangeProcessor
  val oa = new Property(0)
  oa.addObserver(ar.receiveUpdate _)
  oa.setValue2(40)
  println("Should have seen change message")
}
#5

General note: before and after code, please put a line containing nothing but ``` (three backticks) at the start of the line. That means “everything in between here is code”, and it gets formatted properly, which makes it vastly easier to read. You’re likely to get a bit more response if you do this. (Going back and editing your post that way would be appreciated.)

class Property[T](private var _value: T) extends PropertyBase()
with ObserverTrait[PropertyBase] { 
  // <- gives error message: “Type PropertyBase takes
  // type parameters” but I don’t know what that means

This is a major difference between Java and Scala. In Java, type parameters are kind of optional – you can talk about List<T> or just plain List. In Scala, you generally can not do that: you have to specify the type being parameterized over. Scala’s generics are more powerful than Java’s, but they’re also more stringent.

I think you’re getting the error from extends PropertyBase(), which is clearly illegal – you haven’t said PropertyBase of what. This should be extends PropertyBase[T](). I suspect you also need the same in your with clause there.

updateValues(newValue) 
  // <- gives error message “Type mismatch, expected: Nothing, actual: T”
  // but I don’t understand why it’s expecting Nothing

As a rule of thumb, when you get “expected: Nothing” from the compiler, that means you’re assuming that it is inferring some type and not actually getting it.

In this particular case, it looks like a side-effect of the previous error: since you didn’t tell the compiler what it’s a PropertyBase of, it winds up as PropertyBase[Nothing]. So fixing the previous error will probably fix this one.

def receiveUpdate(account: PropertyBase) = 
  // <- gives error message: “Type PropertyBase takes
  // type parameters” but I don’t know what that means

Same problem – there’s no such thing as an unparameterized PropertyBase. I suspect what you actually want is:

def receiveUpdate[T](account: PropertyBase[T]) = ...
#6

It works! here’s the final code just in case anyone wants to see the result.

Thanks everyone for the help. I’ve learned a lot by doing this.

  * Trait to provide observer functionality
  * @tparam S
  */
trait ObserverTrait[S] {
  this: S =>
  private var observers: List[S => Unit] = Nil
  def addObserver(observer: S => Unit) = observers = observer :: observers
  def notifyObservers() = observers.foreach(_.apply(this))
}

/**
  * Class to hold a value and the last value set
  * @param _value the value to set. can be any type
  * @tparam T
  */
abstract class PropertyBase[T](private var _value: T) {
  private var _lastValue: T = _
  def lastValue = _lastValue
  def value = _value
  def updateValues(newValue: T): Unit = {
    _lastValue = _value
    _value = newValue
  }
}

/**
  * Class to take the PropertyBase and add an observer
  * @param _value the value to set. can be any type
  * @tparam T
  */
class Property[T](private var _value: T) extends PropertyBase[T](_value: T)
  with ObserverTrait[PropertyBase[T]] { 
  override def updateValues(newValue: T): Unit = {
    super.updateValues(newValue)
    notifyObservers()
  }
}

/**
  * Sample observer processor class
  */
class ChangeProcessor {
  def receiveUpdate(account: PropertyBase[Int]) = {
    println("Value change: " + account.value.toString)
  }
}

/**
  * Main Test Object
  */
object Main extends App {
  val ar = new ChangeProcessor
  val oa = new Property(0)
  oa.addObserver(ar.receiveUpdate _)
  oa.updateValues(40)
  println("Should have seen change message")
}