Scala, how do I replace static members? - scala

I wan't to build a class Animal which I can find the number of animals were created. In Scala there is no option to static variable, so how can I implement such functionality in Scala (I am looking for non-specific solution)?
Thanks!
For example in Java:
public class Amimal {
static int number_of_aminals = 0;
public Animal() {
number_of_animals++;
}
}

You can create a companion object for your case class which acts as a singleton:
case class Animal(name:String) {
Animal.incrementAnimal
}
object Animal {
def incrementAnimal = ...
}
However, be advised that following the approach above will require you to use mutable variables (variables defined by var instead of val) which is discouraged in Scala. So you may want to revisit your design to use immutable values.

One option would be:
import Animal
class Animal {
Animal.increment()
}
object Animal {
private[this] var _count = 0
def increment(): Unit = { _count += 1 }
def count: Int = _count
}
Though you might want to use AtomicInt.

Related

Modify one value in a Scala class constructor in a concise way

If I want to modify one single parameter in a constructor.
In the Scala case class, the apply method will be overridden twice. Unless apply applies ( no pun ) to auxiliary constructor.
Related to
Modifying case class constructor parameter before setting value
How to override apply in a case class companion
How one can modify one single input from a constructor ?
Criteria :
The class must hold immutable data. All data must be accessible.
Note it doesn't have to be case class.
Additionally , no need to use the apply method.
no extra unused parameters. In the example below, _fistName is still accessible but unused.
case class Person(
lastName: String,
_fistName: String, ... )
{ lazy val fistName = _fistName.toLowerCase }
Here are two simple approaches.
Using class:
class Person(first: String, last: String) {
val firstName = first.toLowerCase
val lastName = last.toLowerCase()
}
val person = new Person("Adam", "Smith")
println(person.firstName + " " + person.lastName) // adam smith
Using trait + object's apply():
trait Person {
val firstName: String
val lastName: String
}
object Person {
def apply(first: String, last: String) = new Person {
override val firstName: String = first.toLowerCase
override val lastName: String = last.toLowerCase
}
}
val person = Person("Adam", "Smith")
println(person.firstName + " " + person.lastName) // adam smith
Note that classes must be instantiated with new, while traits (created with apply()) don't.
Why no case classes? Well, they are designed to serve as ADTs (abstract data types). Basically, they are thought of as containers for some data without any logic. That's why they get apply() out-of-the-box. If you want to override it, then means your class doesn't have the semantics of a case class.
I can see that #prayag took the effort of trying to help you force it into a case class, but seriously, if it doesn't have to be one (and you said so in the question), then don't make it one.
The reference you had posted seems to have lot of answers as well.
Two simple ways I could think of
make it abstract case class and define companion object which would mutate the value you want
define the member of case class as var and mutate it.
eg. (using scalatest)
class CaseClassSpecs extends FunSpec {
describe("case class modify") {
it("APPROACH 1 : modifies abstract case class member") {
object Item {
def apply(itemId: String, itemName: String) :Item = new Item(itemId.toLowerCase, itemName) {}
}
abstract case class Item private (val itemId: String, itemName: String)
val item1 = Item("SKU-ONE", "Shirts")
assert(item1.itemId == "sku-one")
assert(item1.itemName == "Shirts")
}
it("APPROACH 2 : modifies case class member which is var") {
case class Item (var itemId: String, itemName: String) {
itemId = itemId.toLowerCase()
}
val item1 = Item("SKU-ONE", "Shirts")
assert(item1.itemId == "sku-one")
assert(item1.itemName == "Shirts")
}
}
}
Class parameters are not necessarily class members. You can have class parameters that do not become class members.
Method 1
class Foo(bar0: String) {
val bar = bar0.toLowerCase()
}
#main
def main(): Unit = {
println(Foo("AsDfGh").bar)
}
prints:
asdfgh
and the decompiled code is:
public class Foo {
private final String bar;
public Foo(final String bar0) {
this.bar = bar0.toLowerCase();
}
public String bar() {
return this.bar;
}
}
You see, bar0 is a "temporary" value, it does not become a field because it is not referenced.
So if you want to change a value, just do not use the original value in the methods.
Method 2
For case classes, it does not seem to work in 2022, but here is another trick:
case class Point (x: Double, y: Double)
class PolarPoint(r: Double, alpha: Double) extends Point(r*Math.cos(alpha), r*Math.sin(alpha))
Here r and alpha do not become members of PolarPoint.
If you don't need two types, you can make the 1st constructor protected:
case class Foo protected(x:Int)
class FooImpl(x0:Int) extends Foo(myFunc(x0))
You will reference objects as Foos but create FooImpls.
Method 3
Your class can have multiple parameter lists and implicits:
class Qux(x:String)(implicit val y:String = x.toLowerCase())
is converted to:
public class Qux {
private final String y;
public static String $lessinit$greater$default$2(String var0) {
return Qux$.MODULE$.$lessinit$greater$default$2(var0);
}
public Qux(final String x, final String y) {
this.y = y;
}
public String y() {
return this.y;
}
}
You see that here only y becomes a field.

How do I call an auxiliary base-class constructor from a derived-class auxiliary constructor in Scala?

You can call an auxiliary constructor in the base class via the derived class primary constructor:
class Base(n:Int) {
def this(n:Int, i:Int) = {
this(n)
println(i)
}
}
class Derived(n:Int, i:Int) extends Base(n, i)
Is there a syntax for calling an auxiliary base-class constructor from an auxiliary derived-class constructor? This doesn't work:
class Derived2(n:Int) extends Base(n) {
def this(n:Int, i:Int) = {
super.this(n, i) // Can't do this
println(i)
}
}
In other languages, you can do this, but you must call the base-class constructor first, which is why I tried to do it here.
Note that I am looking for the syntax for the call rather than alternative ways to achieve the same result.
In Scala you have to go through the default constructor no matter what, which forces you to choose one super construction in your class instantiation. This is basically what you're trying to do in terms of java:
public class Derived2 extends Base {
public Derived2(int n, int i) {
super(n, i);
}
public Derived2(int n) {
super(n);
}
}
Since in Scala you have to go through the default constructor this is what's happening:
public class Derived2 extends Base {
public Derived2(int n, int i) {
this(n);
super(n, i); //does not compile
}
public Derived2(int n) {
super(n);
}
}
So, as is normal in Java, you can only call super or this as the first line of your constructor implementation. Since Scala forces the call to the default constructor, there's no way around only using one implementation of the Base constructor.
There is no work around, as this isn't really dogmatic Scala. I would suggest changing your design here. Inheritance in Scala is usually done through traits, not classes or abstract classes.
Here's what an alternative might look like using a trait:
trait Base2 {
val a:Int
}
class Derived3(n: Int) extends Base2 {
val a = n
def this(n: Int, i: Int) = {
this(n)
}
}

Why can't I access my objects member variable?

I have the following class setup:
class MyClass {
class MyInnerClass(memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
Then I have the following code outside of the class:
def myFunction = {
val a = new MyClass
val b = a.getAInner.memberVar // value memberVar is not a member of a.MyInnerClass
}
Why is this?
You need to add the keyword val to make memberVar public otherwise it's a private value:
class MyClass {
class MyInnerClass(val memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
#Noah's answer is totally correct, but I would also throw out the option of using case class. See here for some of the sugar it provides. I use it almost reflexively. In your example, it would be:
object MyClass {
case class MyInnerClass(memberVar: String)
def getAInner: MyInnerClass = {
new MyInnerClass("hello")
}
}
def myFunction = {
val b = MyClass.getAInner.memberVar
}
I tend to do it this way because invariably, I want to take advantage of the sane defaults case class provides.
I also chose to use object for the outer type, because it doesn't have any parameters, although you may have just done that for simplicity's sake.

Protected abstract vars in Scala can be implemented public?

Could someone explain why scala would allow a public variable, to satisfy the implementation of an abstract declared Protected item? My first assumption is that the compiler would complain, but I created a small test to see if this worked, and to my surprise it does. Is there an advantage to this? (perhaps this is normal in OOP?) Any methods to avoid the accidental pitfall?
object NameConflict extends App {
abstract class A {
protected[this] var name:String
def speak = println(name)
}
class B(var name:String) extends A { //notice we've declared a public var
}
val t = new B("Tim")
t.speak
println(t.name) // name is exposed now?
}
It's normal and as in Java. Sometimes it's desirable to increase the visibility of a member.
You can't do it the other way around and turn down visibility in a subclass, because the member can by definition be accessed through the supertype.
If invoking a method has terrible consequences, keep the method private and use a template method that can be overridden; the default implementation would invoke the dangerous method.
abstract class A {
private[this] def dangerous = ???
final protected def process: Int = {
dangerous
template
}
protected def template: Int = ???
}
class B extends A {
override def template = 5
}

How to translate the following class definition from Java to Scala?

I am learning Scala and I cannot figure out how to translate the following Java code into Scala:
class Parent {
Parent(int i) {}
}
public class Test extends Parent {
final static int I = 1;
Test() {
super(I);
}
}
Please help me, thanks.
Here are my failed attempts:
1.
class Parent(val i: Int) {}
object Test {
val I = 1
}
class Test extends Parent(I) {
}
2.
class Parent(val i: Int) {}
class Test extends Parent(I) {
val I = 1
}
class Parent(i: Int)
class Test extends Parent(Test.I) // `super` is done in the parent's constructor
object Test {
val I = 1 // `static` members go in an `object`
}
Note:
You don't actually need the empty braces.
Only declare i with val if you want it to be publicly accessible (but not modifiable). It's private by default.