In Scala I need to do something like following code in Java does:
public class A {
private String text;
public A(String text) {
this.text = text;
}
}
How can achieve that in Scala?
I know that I can use class A(text: String) { ... }, but this is only a very simplified example and not real case.
I have tried the following and it prints always null:
class A {
var text: String = null
def this(text: String) = {
this()
this.text = text
}
println(text)
}
Thanks for help.
In Scala classes have only one main constructor, and it's exactly what you define like this: class A(text: String) { ... }. All other constructors should call it at first and then do their own stuff.
All expressions in the body of the class are treated as body of the main constructor. So println(text) in you case is in the body of the main constructor. You call this() in your def this(text: String) constructor at first, so println is executed and only then you initialize text field.
From my point of view, main constructor can satisfy most of the real-life use-cases (especially with default and named arguments). So can you please elaborate on this and explain why you need the second one? Maybe we can find beter solution for the problem you are facing there.
Update regarding the comment
If you want to provide a set of optional arguments during construction time, then I recommend you to use Option instead of null values. So you can implement your A class like this:
class A(val a: Option[String] = None, val b: Option[Int] = None, c: Option[Double] = Some(2.0))
new A(b = Some(10))
All fields are now constant and have some default, but you can customize some of them. It's also possible that some combination of arguments are mutually exclusive, according to some business logic, for example. In this case it's reasonable to use several constructors. But even better solution can be to create several factory methods in companion object of the class and make constructor private. For example, if users of the class are allowed to provide either a and b or c, then you can write something like this:
class A private (val a: Option[String] = None, val b: Option[Int] = None, c: Option[Double] = Some(2.0))
object A {
def apply(a: String, b: Int) = new A(Some(a), Some(b))
def apply(c: Double) = new A(c = Some(c))
}
A("test", 1)
A(11.1)
class A {
var text: String = null
def this(text: String) = {
this()
this.text = text
println(text)
}
}
or
class A(text:String=""){
println(text)
}
or
class A(text:String=null){
println(text)
}
The correct way to do that is :
class A( text : String) {
def this() = this("") // or null
}
As Tenshi said, the default constructor is the A(text : String) and all other constructors, for instance this() must call it first.
Related
I have some code that uses both a third-party library and my own library. In my own library, I don't want to have a dependency on the third-party one so I want one of my methods to accept a more generic type as a parameter. Unfortunately, I cannot extend or mixin a trait to the 3rd party classes since they are generated using factory methods & the classes are final.
I can get around this issue by using structural typing but I was wondering if there is an alternative? I don't want to have to iterate through each record returned by the factory method and "new up" instances of a separate type if possible.
I've boiled it down to a scenario like the following:
Third-party library code that cannot be changed
// Class inside library cannot be extended due to it being 'final'
final class SpecificRecord(val values: IndexedSeq[String]) {
def get(i: Int): String = {
values(i)
}
}
// A companion object simply to create some sample data in an iterator
object SpecificRecord{
def generateSpecificRecords(): Iterator[SpecificRecord] = new Iterator[SpecificRecord] {
var pointerLocation: Int = 0
private val state = IndexedSeq(
IndexedSeq("Row1 Col1", "Row1 Col2", "Row 1 Col3"),
IndexedSeq("Row2 Col1", "Row2 Col2", "Row 2 Col3")
)
override def hasNext: Boolean = {
if (pointerLocation < state.length) true else false
}
override def next(): SpecificRecord = {
val record = new SpecificRecord(state(pointerLocation))
pointerLocation += 1
record
}
}
}
As you can see above, the SpecificRecord class is final and the specificRecords val is an Iterator with a bunch of SpecificRecord in it. I don't want to have to iterate through each specificRecord and create a new, more generic, object if possible.
My code that can be changed
val specificRecords: Iterator[SpecificRecord] = SpecificRecord.generateSpecificRecords()
type gettable = {
def get(i: Int): String
}
def printRecord(records: Iterator[gettable]): Unit = {
for (record <- records) {
println(record.get(0), record.get(1), record.get(2))
}
}
printRecord(specificRecords)
This correctly prints:
(Row1 Col1,Row1 Col2,Row 1 Col3)
(Row2 Col1,Row2 Col2,Row 2 Col3)
I have a printRecord method that doesn't really care what type is passed in, as long as it has a method like get(Int): String. This a pretty decent solution but I was wondering if it would be possible to do this without structural typing?
This is a typical use case for type classes.
trait Gettable[T] {
def get(t: T, i: Int): String
}
object Gettable {
implicit object SpecificRecordGettable extends Gettable[SpecificRecord] {
def get(sr: SpecificRecord, i: Int) = sr.get(i)
}
}
def printRecord[T : Gettable](records: Iterator[T]) = {
val getter = implicitly[Gettable[T]]
records.foreach { record =>
println(getter.get(record, 0), getter.get(record, 1), getter.get(record, 2))
}
}
This is a bit more verbose than your approach with structured types: for each type you want to be gettable, you have to add an implicit object implementing the get, but it works without reflection, which is a good thing.
Another advantage of this approach is its flexibility: the underlying type does not have to have get specifically, you can implement anything with the implicit. E.g.:
implicit object ArrayGettable extends Gettable[Array[String]] {
def get(a: Array[String], i: Int) = a(i)
}
implicit object ProductGettable extends Gettable[Product] {
def get(p: Product, i: Int) = p.productIterator.drop(i).next.toString
}
Now, your printRecord works with string arrays too (as long as they have at least three elements), and even tuples and case classes.
Try this:
printRecord[Product](Iterator((1,2, "three"), ("foo", "bar", 5)))
Or this:
case class Foo(x: String, y: Int, z: Seq[Int])
printRecord[Product](Iterator(Foo("bar", 1, 1::2::Nil), ("foo", "bar", "baz")))
A similar but a little bit less verbose approach is to just define an implicit 'getter' without bothering with type classes:
def printRecord[T](records: Iterator[T])(implicit getter: (T,Int) => String) =
records.foreach { record =>
println(getter(record, 0), getter(record, 1), getter(record, 2))
}
object Getters {
implicit def getter(sr: SpecificRecord, i: Int) = sr.get(i)
implicit def getter(a: Array[String], i: Int) = a(i)
implicit def getter(p: Product, i: Int) = p.productIterator.drop(i).next.toString
}
This is fairly equivalent in usage, the difference being that type class lets you potentially define more than one method, but if you only ever need get, then this would save you a few keystrokes.
I have written the following class and corresponding companion object:
class Tile(val tileCoordinate: Int, val pieceOnTile: Piece) {
override def toString(): String = {
if(isOccupied()) {
pieceOnTile.toString()
}
"-"
}
def isOccupied(): Boolean = pieceOnTile != null
}
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = {
new Tile(coordinate, piece)
}
def apply(coordinate: Int): Tile = {
new Tile(coordinate, ??) // what is the best design here?An Option?
}
}
My question is, when the factory method to create a Tile without a piece on it is invoked, what is the appropriate argument to pass in to the Tile constructor? I don't want to pass in null, that seems like a poor design choice. Should I have the main constructor take an Option[Piece] and pass in None?
That seems sort of ugly too because when I want to create a tile I'd need to say:
val t = Tile(1, Some(new Knight()));
Personally I would ditch the class and companion object completely, and instead go for a case class:
case class Tile(tileCoordinate: Int, pieceOnTile: Option[Piece] = None) {
override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")
}
This allows you to later do the following when checking for values:
... match {
case Tile(c, Some(p)) => ...
case Tile(c, None) => ...
}
Having the second parameter default to None allows you to call it as Tile(coord), Tile(coord, None) and Tile(coord, Some(piece))
I would code the following:
class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) {
// A little bit more scala-idiomatic, and a probable bug corrected
override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")
def isOccupied : Boolean = pieceOnTile.isDefined
}
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = {
new Tile(coordinate, Some(piece))
}
def apply(coordinate: Int): Tile = {
new Tile(coordinate, None)
}
}
If pieceOnTile is optional, then you should use Option for sure. If you don't like the ugliness of having to wrap the Pieces in Some when creating new instances of Tile, then hide it within apply:
class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) { ... }
object Tile {
def apply(coordinate: Int, piece: Piece): Tile = new Tile(coordinate, Some(piece))
def apply(coordinate: Int): Tile = new Tile(coordinate, None)
}
Then even isOccupied will look more scala-like:
def isOccupied() : Boolean = pieceOnTile.isDefined
Another alternative could be to define empty/occupied cases as separate case classes:
sealed abstract class Tile(val isOccupied: Boolean)
case object EmptyTile extends Tile(false) {
override def toString: String = "-"
}
case class OccupiedTile(piece: Piece) extends Tile(true) {
override def toString: String = piece.toString
}
You can use EmptyTile, create OccupiedTile(piece) and you can check a Tile either by the isOccupied flag or by pattern matching.
One possible advantage of this approach is that if you add more methods that assume a contained piece, you will not have to add checks of occupiedness to each method because you could define them only in OccupiedTile in the first place.
Using Scala, I want to achieve the following:
// SETUP:
implicit class ExampleOps(s: String) {
def name: String = ???
}
case class Example(prop1: String, prop2: String)
val e = Example("a", "b")
// BEHAVIOR I WANT:
e.prop1.name // should return "prop1"
In this case def name somehow knows what it's being called on. How is this accomplished?
As I explained in the comment, macros could be used to a certain extent. However, they can not magically restore some information that is lost. For example if you store the property value in an arbitrary variable, there is no way to figure out from which property it was read:
val x: String = e.prop1
x.name // no way to know if came from calling e.prop1
So I think the only solution is to use a custom type. You could allow them to be unrolled as strings implicitly:
object Property {
implicit def value[A](prop: Property[A]): A = prop.value
}
case class Property[+A](name: String, value: A)
case class Example(value1: String, value2: String) {
def prop1 = Property("prop1", value1)
def prop2 = Property("prop2", value2)
}
val e = Example("a", "b")
e.prop1.toUpperCase
e.prop1.name
I am using case classes for models in an ORM. Each model has an id, but the id shouldn't be publicly accessible. So I have a parent trait
trait WithId {
private var id: Long = 0
}
and a lot of case classes (the models) inheriting from it
case class C1(a: Int, b: String) extends WithId
case class C2(...) extends WithId
...
Now, if someone calls copy() on a case class, it doesn't copy the id with it, but sets it to 0.
val c1 = C1(3, "bla")
//Set c1.id to a value != 0
val c2 = c1.copy(b="bla2")
//c1.id !=0, but c2.id = 0
I want it to copy the id as well.
Since I have a lot of these case classes, I'd prefer to have as few code as possible in the case classes themselves. So implementing a copy() method in each case class would be a lot of boilerplate code.
Is there a way to implement something in the trait that makes copy() also copy the id? Maybe something using macros? Or is there another way I didn't think about at all?
edit:
I could override the id field in each case class like
case class C1(a: Int, b: String, protected var id: Long)
Then it would be copied. But that also is boilerplate code I have to write per case class and it's hard to explain why you have to add an id field to a case class although you never notice it or can use it anywhere else when using the case class. I'd like to avoid that if possible.
If I were you, I'd add an ID-carrying token:
class IdToken private[myPackage] (val id: Int) {
override def equals(a: Any) = a match {
case tok: IdToken => id == tok.id
case _ => false
}
override def hashCode = id.hashCode ^ 0x157135
override def toString = ""
}
object IdToken {
private var lastId = 0
private[myPackage] def next = { lastId += 1; new IdToken(lastId) }
}
Since the constructor is private to your package, nobody else but you can create these tokens.
Then you write your trait as
trait WithID { protected def idToken: IdToken }
and
case class C1(a: Int, b: String, protected val idToken: IdToken = IdToken.next) extends WithID {
def checkId = idToken.id
}
(where you only need checkId for the test below) so you can
scala> C1(5, "fish")
res1: C1 = C1(5,fish,)
scala> res1.copy(a = 3)
res2: C1 = C1(3,fish,)
scala> res1.checkId == res2.checkId
res3: Boolean = true
But you can't access the token from outside code because the val is protected.
Hopefully that is good enough encapsulation.
I know that we can overload class constructor in Scala as follows-
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
But how can I overload a class which have two completely different types of parameters as below (imagine that I can identify an user either by name or numeric id)
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
(imagine that I can identify an user either by name or numeric id)
You almost certainly don't want to do this by having optional fields in your class. Rather, you should encode the fact that the user is identified in various ways into the types and structure of your program.
One way to do this is to encode the user identifier using Scala's built-in Either type:
class User private(identifier : Either[String, Int]) {
def this(id : Int) = this(Right(id))
def this(name : String) = this(Left(name))
}
However, you might also want to make the nature of the user identifier a little more explicit, and encode it as your own Algebraic data type:
trait UserIdentifier
object UserIdentifier {
case class ById(id : Int) extends UserIdentifier
case class ByName(name : String) extends UserIdentifier
}
class User(id : UserIdentifier) {
def this(id : Int) = this(UserIdentifier.ById(id))
def this(name : String) = this(UserIdentifier.ByName(name))
}
By doing it this way, you prevent problems such as somebody trying to look up a name on a User which is identified by an id instead. The second approach also allows you to extend the idea of a UserIdentifier in the future, in case a user can be identified by some other construct.
Alternativelly, you can do this
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int)
class UserS(userName: String)
}
And use it this way:
val u1 = User(1)
val u2 = User("a")
If you have a lot of common logic you can put it into a common abstract class
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int) extends AUser
class UserS(userName: String) extends AUser
abstract class AUser{
// common logic for both classes
}
}
You can do this:
class User private() {
def this( userName: String ) = { this(); ??? }
def this( userId: Int ) = { this(); ??? }
}
the private keyword makes the no-arg constructor private. This means your other secondary constructors don't need to pass anything to the primary constructor
(effectively making the two secondary constructors independant), but the callers still cannot instantiate the class withouth passing any parameter.
Note that this pattern can be tricky to use when your class has vals to initialize from the construtors parameters.