Can I in Scala declare the class inside its companion object? - scala

While fighting with my private immutable class constructor, and the constraint that auxiliary constructors have to call each other as first statement, without anything else from the class in scope, I seem to be constrained to use a companion object for my instantiations, and since my companion object would have to access the main constructor, I need the private keyword to target a scope including that object.
Now, my brain is weak in name generation, and I am trying to save the need of an enclosing namespace for both that companion object and the class by placing my class within the companion object itself, this way:
object Group {
private def complexComputeX(z: Int) = z
private def complexComputeY(x: Int, z: Int) = x + z
def apply(z: Int) = {
val x = complexComputeX(z)
val y = complexComputeY(x, z)
new Group(x, y)
}
class Group private[Group](x: Int, y: Int) {
//...
}
}
val x = Group(5)
//...
The problem is that the Group of private[Group] does not reference the object, but still the class (making it superfluous).
How can I tag that constructor to be available at the companion object level, but not outside it?
PS: that companion object is already giving me headache, and I would even have preferred to have just the class, en-scoping there the complexCompute, which several constructors implementations could need...
EDIT: Okay. Just while adding the tags I hit a neuron ringing me that a companion object might have some privilege over the class' scope. It can access its private parts, and so I can simply have object and class side to side without dedicated enclosing scope. However, I maintain the question, for both a response on possibility way to handle scoping for such boxing cases object Main {object Main {object Main... and for chances of remarks about techniques for having only constructors in the class without any companion object.

Your Group object is not the companion object of your Group class as they are not in the same namespace.
You don't have to provide a scope to the private modifier. If you leave it empty, it's only accessible by this class and its companion object.
object Something {
class Group private(x: Int, y: Int)
object Group {
private def complexComputeX(z: Int) = z
private def complexComputeY(x: Int, z: Int) = x + z
def apply(z: Int) = {
val x = complexComputeX(z)
val y = complexComputeY(x, z)
new Group(x, y)
}
}
val x = Group(5)
// This line doesn't compile
new Group(42, 45)
}

The companion object's private are also accessible from the class, so I have this other option, concerning my root problem:
object Group {
private def computeX(z: Int) = z
private def computeY(x: Int, z: Int) = x + z
private def computeXY(z: Int) = {
val x = computeX(z)
(x, computeY(x, z))
}
}
class Group private (x: Int, y: Int) {
private def this(xy: (Int, Int)) = this(xy._1, xy._2)
def this(z: Int) = this(Group.computeXY(z))
}
val group = new Group(5)
That the companion object makes a full privatable scope available from my constructors makes me breath better. In my full case I was indeed also going to need types I wanted private too. The fact that I am forced to create a companion to contain this locally useful scope might not be so important now, I guess.
However, the use of the tuple makes it more cumbersome than Dimitri's option.

Related

how to call a subclass constructor with constrained access?

I have something like below that I want to compile
trait T{
def a: Int
}
class A private(val a: Int, a2: Int) extends T{
def add(b: Int): A = new A(a + b, a2 + 2*b)
}
object T{
def make(a: Int): A = {
new A(a, 2*a) // doesn't compile
}
Here class A has a private constructor because I want the only way to construct a A is to pass through the constructor T.make or with the updated method A.add (which in this example both garantie that a2 = 2*a).
But because A constructor is private, it cannot be access by the parent trait T. Same goes for protected. Basically, I would need an inversed protected?
Note: A solution that is not satisfying is to lower (too much) the restriction on A constructor, maybe to package-private. But I don't want any other construction possible but the ones that were planned. I could lower the constraint to all code in the current file, but I don't know how to do that either.
A few options.
You can rename your object T to object A - then it will have access to A's private members
You can make class A inner to object T - then you can make the constructor private[T], and T will have access to it.
You can also make it package-private. You are mistaken when you say that it would be "lowering restriction too much". A package in scala doesn't have to be an entire directory. It doesn't even need to be the whole file. You have complete control over its content, and the purpose of that is to be able to do exactly what you are trying to do here.
Maybe you should put make(..) into companion object of class A rather than companion object of trait T.
object A {
def make(a: Int): A = {
new A(a, 2 * a)
}
}

Access field from trait in companion object

I have something like the following code (I simplified it):
trait A {
val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int) = B(someValue, Array.ofDim[Array[Byte]](someValue).map(block => Array.fill[Byte](A.CONST_VALUE)(0)))
}
Basically, I declared a constant CONST_VALUE in the trait A. I am trying to use it in the companion object B to instantiate the class B. However, I can't access A.CONST_VALUE from the companion object B.(I'm getting a compilation error).
So how could I do this?
You can't do this.
First of all, object B is the companion object to class B, not to trait A. Companions need to have the same name and be defined in the same compilation unit.
Secondly, CONST_VALUE is an instance field of trait A. It is a member of an instance of A, not a member of A.
Thirdly, when you say A.CONST_VALUE you are basically calling the method CONST_VALUE on A. But you can only call methods on objects/values. A is not an object, it is a type, types and values live in different worlds, you cannot mix the two.
And fourth, your CONSTANT_VALUE is misleadingly named: only final vals are constant value definitions, so your CONSTANT_VALUE is not actually a constant value.
Fifth, your apply method calls itself (B() is syntactic sugar for B.apply()), and thus needs a return type annotation.
Sixth, your apply method calls itself with two arguments, but it is defined with only one parameter.
Seventh, you create an Array[Array[Byte]], but it is not clear to me why you want to do that and what you need it for.
That's a whole truckload of problems (especially considering that there are only a handful of lines of code to begin with), which you need to fix one-by-one. Here's one possible partial solution, but it is not clear to me what it is exactly that you are trying to achieve.
trait A
object A {
final val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int): B = new B(
someValue,
Array.ofDim[Array[Byte]](someValue).map(block => Array.fill[Byte](A.CONST_VALUE)(0)))
}
Declare val CONST_VALUE = 10 inside the companion object A instead of trait A. Also corrected the apply method definition in object B
trait A {
}
object A {
final val CONST_VALUE = 10
}
class B(someValue: Int, values: Array[Int]) extends A {
//some methods
}
object B {
def apply(someValue: Int) = new B(someValue, Array.ofDim[Int](someValue).flatMap(block => Array.fill[Int](A.CONST_VALUE)(0)))
}

Accessibility of primary constructor parameters in scala

I am having hard time to understand the concept of primary constructor and it's parameters. What I have understood till now is: if we define a class as following
class Example(a: Int, b: Int)
Scala compiler generates a primary constructor of the class Examples with the above two parameters. But, it doesn't defines fields a and b in the class Example's definition. But if we define
class Example(val a: Int, val b: Int)
scala compiler generates the primary constructor as above and adds two fields in the class definition.
Now the problem comes when I am trying an example like
class PrimaryConstructor(a: Int, b: Int){
override def toString() = "PrimaryConstructor(" + this.a + ", " + this.b + ")"
}
The above code compiles well even if there is no fields named either a or b. I am not able to understand that if there are no any fields as such then how I am able to access them using this: the current object reference.
object Main{
def main(args: Array[String]){
val primaryConstructor = new PrimaryConstructor(1, 2)
println(primaryConstructor.a)
}
}
While if I try to access them from out side the class definition as above, I get the following error message after compilation.
error: value a is not a member of PrimaryConstructor
println(primaryConstructor.a)
I can understand this. But, how can I access those fields using this? Please help me to understand this.
It basically generates a private val, so
class A(a:Int) {
def func = a
}
and
class A(private[this] val a:Int) {
def func = a
}
are equivalent. This may not be entirely true if you omit the function.
When a constructor parameter is referred outside the constructor body ( such as in example func above ), Scala generates a private[this] val, otherwise not.
You can check scala spec for more details or look at this stackoverflow question
Martin's answer is great:
It basically generates a private val, so
class A(a:Int) {
def func = a
}
and
class A(private[this] val a:Int) {
def func = a
}
are equivalent and you can access a from inside your class.
But, note that class A(a: Int) means that the field a is instance private. Meaning that you cannot write something like this:
class A(a: Int){
def sum(other: A): Int = {
this.a + other.a
}
}
other.a is not allowed even though both instances are of the same type. You can only use this.a.

How to create a Scala class with private field with public getter, and primary constructor taking a parameter of the same name

Search results so far have led me to believe this is impossible without either a non-primary constructor
class Foo { // NOT OK: 2 extra lines--doesn't leverage Scala's conciseness
private var _x = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
or sacrificing the name of the parameter in the primary constructor (making calls using named parameters ugly)
class Foo(private var _x: Int) { // OK: concise
def x = _x
}
val f = new Foo(_x = 123) // NOT OK: named parameter should be 'x' not '_x'
ideally, one could do something like this:
class Foo(private var x: Int) { // OK: concise
// make just the getter public
public x
}
val f = new Foo(x = 123) // OK: named parameter is 'x'
I know named parameters are a new thing in the Java world, so it's probably not that important to most, but coming from a language where named parameters are more popular (Python), this issue immediately pops up.
So my question is: is this possible? (probably not), and if not, why is such an (in my opinion) important use case left uncovered by the language design? By that, I mean that the code either has to sacrifice clean naming or concise definitions, which is a hallmark of Scala.
P.S. Consider the case where a public field needs suddenly to be made private, while keeping the getter public, in which case the developer has to change 1 line and add 3 lines to achieve the effect while keeping the interface identical:
class Foo(var x: Int) {} // no boilerplate
->
class Foo { // lots of boilerplate
private var _x: Int = 0
def this(x: Int) { this(); _x = x }
def x = _x
}
Whether this is indeed a design flaw is rather debatable. One would consider that complicating the syntax to allow this particular use case is not worthwhile.
Also, Scala is after all a predominantly functional language, so the presence of vars in your program should not be that frequent, again raising the question if this particular use case needs to be handled in a special way.
However, it seems that a simple solution to your problem would be to use an apply method in the companion object:
class Foo private(private var _x: Int) {
def x = _x
}
object Foo {
def apply(x: Int): Foo = new Foo(x)
}
Usage:
val f = Foo(x = 3)
println(f.x)
LATER EDIT:
Here is a solution similar to what you originally requested, but that changes the naming a bit:
class Foo(initialX: Int) {
private var _x = initialX
def x = _x
}
Usage:
val f = new Foo(initialX = 3)
The concept you are trying to express, which is an object whose state is mutable from within the object and yet immutable from the perspective of other objects ... that would probably be expressed as an Akka actor within the context of an actor system. Outside the context of an actor system, it would seem to be a Java conception of what it means to be an object, transplanted to Scala.
import akka.actor.Actor
class Foo(var x: Int) extends Actor {
import Foo._
def receive = {
case WhatIsX => sender ! x
}
}
object Foo {
object WhatIsX
}
Not sure about earlier versions, but In Scala 3 it can easily be implemented like follows:
// class with no argument constructor
class Foo {
// prive field
private var _x: Int = 0
// public getter
def x: Int = _x
// public setter
def x_=(newValue: Int): Unit =
_x = newValue
//auxiliary constructor
def this(value: Int) =
this()
_x = value
}
Note
Any definition within the primary constructor makes the definition public, unless you prepend it with private modifier
Append _= after a method name with Unit return type to make it a setter
Prepending a constructor parameter neither with val nor with var, makes it private
Then it follows:
val noArgFoo = Foo() // no argument case
println(noArgFoo.x) // the public getter prints 0
val withArgFoo = Foo(5) // with argument case
println(withArgFoo.x) // the public getter prints 5
noArgFoo.x = 100 // use the public setter to update x value
println(noArgFoo.x) // the public getter prints 100
withArgFoo.x = 1000 // use the public setter to update x value
println(withArgFoo.x) // the public getter prints 1000
This solution is exactly what you asked; in a principled way and without any ad hoc workaround e.g. using companion objects and the apply method.

Enhance java classes using traits, how to declare inside trait the java fields?

My goal is to enhance inside scala code an existing Java class using a trait mix-in. For example to add a method like java.awt.Rectangle.translate(dx, dy) to java.awt.geom.Ellipse2D class. For this I create the following trait:
trait RectangleLike {
var x: Double // abstract vals to correspond to java class fields
var y: Double // I need these vars to refer to them inside translate method
def translate(dx: Double, dy: Double) {
x = x + dx
y = y + dy
}
// more concrete trait methods here
} // defines without errors in scala REPL
Then use the trait when constructing an Ellipse:
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
However when I execute the above script in scala REPL I get the following output:
<console>:8: error: overriding variable x in trait RectangleLike of type Double;
variable x in class Double of type Double has incompatible type;
other members with override errors are: y
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
I suspect that this error is due to the way Scala implements vars - as a private field and a getter/setter pair of methods. Is what I try to achieve doable? Is there another way to define the java class fields in the trait and then refer to them inside the concrete trait methods?
Thanks in advance
Jack Dimas
Yes, it is doable but instead of trying to access the private fields of the classes you want to mix in with (which is most likely a bad idea anyway), you would want to declare the self-type of RectangleLike to be java.awt.geom.RectangularShape so that you can use your trait with e.g. Ellipse2D.Double just as well as with Rectangle2D.Double.
Here is how it works:
trait RectangleLike {
self: java.awt.geom.RectangularShape =>
def translate(dx: Double, dy: Double) {
setFrame(getX + dx, getY + dy, getX + getWidth, getY + getHeight)
}
}
object Test {
val foo = new java.awt.geom.Ellipse2D.Double with RectangleLike
}
By saying self: java.awt.geom.RectangularShape => you declare the self-type of your trait which enables you to access all corresponding methods like the necessary getters and setters, allows for using your trait with all descendants of RectangularShape, and also "restricts" your trait so that it can only be used as a mixin to classes which themselves are subtypes of RectangularShape.
The alternative to the above scenario is using a so-called view of your RectangularShape which is a common paradigm as well. For this, you would e.g. declare a class
class RichRectangularShape(shape: java.awt.geom.RectangularShape) {
def translate(dx: Double, dy: Double) {
shape.setFrame(shape.getX + dx, shape.getY + dy,
shape.getX + shape.getWidth, shape.getY + shape.getHeight)
}
}
Scala has a way of implicitly viewing an object of one type as an object of another type. If you happen to call a method on a object which is not declared in its corresponding type, the compiler trys to find a type that provides this method and in particular also trys to find an implicit conversion so that your original object can be viewed as an instance of the latter type. For this to work, you would typically declare the companion object of RichRectangularShape as something like this:
object RichRectangularShape {
implicit def mkRRS(shape: java.awt.geom.RectangularShape): RichRectangularShape =
new RichRectangularShape(shape)
}
Then:
scala> import RichRectangularShape._
import RichRectangularShape._
scala> val foo = new java.awt.geom.Ellipse2D.Double
foo: java.awt.geom.Ellipse2D.Double = java.awt.geom.Ellipse2D$Double#0
scala> foo.translate(5,2)
scala> foo.getX
res1: Double = 5.0
scala> foo.getY
res2: Double = 2.0
scala> :t foo
java.awt.geom.Ellipse2D.Double
Indeed impressive explanation and example!
I have one little problem with this approach, the translate method includes the real calculation that I would like to avoid. Yes in this case it is very simple but generally speaking such method may be complicated and lead to the serious development. Therefore I suggest the following approach:
trait RectangleLike extends java.awt.geom.RectangularShape {
def translate(dx: Int, dy: Int): Unit = {
val rect = new java.awt.Rectangle
rect.setRect(getX, getY, getWidth, getHeight)
rect.translate(dx,dy)
setFrame(rect.getX, rect.getY, rect.getWidth, rect.getHeight)
}
}
In this way I am using the original translate calculation.