Mutable or Immutable class below? - oop

In object-oriented and functional programming, an immutable object is
an object whose state cannot be modified after it is created. This is
in contrast to a mutable object, which can be modified after it is
created.
Mutable or Immutable class below? I think it's mutable because static field singleton changes after new MavenPush(project), but I need 100% correct answer. It's groovy code, but it's like Java code
final class MavenPush {
private static volatile MavenPush singleton = null
private final def project
private MavenPush(project) {
this.project = project
}
static MavenPush with(project) {
if (singleton == null) {
synchronized (MavenPush.class) {
if (singleton == null) {
singleton = new MavenPush(project)
}
}
}
return singleton
}
}

An instance of the class is immutable, the class is mutable as a field of the class gets mutated.

This is an immutable instance; but also useless - there are no getters (unless groovy does that implicitly - I am not aware if this happens).

As stated already, the instances of the class look immutable (final properties can only be initialized in the c'tor). But since you left the type out for project this really depends on that. If you pass a String you really have something immutable (Java strings are immutable) - if not: this is basically just an immutable reference to something mutable and all your expectiations about that may shatter at some point.
Now for that static member:
From an OO view, singleton seems like the wrong name. The singleton pattern is quite well known, but what you have here, is a "last item changed cache".
From an FP view: with is often used in a context, where you want to create a modified version of immutable data. So if you run with from instances you earlier got, you dont "copy and change" from the instance but from your "global last item cache (singleton)" - that is no problem with the simple example (just one property), but might be with the "real code".

Related

Kotlin: variable in enum class can't be changed after initialization

When writing this example into the IDE:
enum class EnumTest {
FOO, BAR;
lateinit var foobar: String
}
I get the message With old Native GC, variable in enum class can't be changed after initialization on the "foobar" variable. I can't find anything about this message online. Also everything seems to work just fine, so my question is:
When and how does this affect me?
Thank you!
You could declare your values in a singleton object, set them there and reference it in the enum.
object Constants {
var FOO_STR = "bla"
var BAR_STR = "bar"
}
enum class EnumTest(val foobar: String) {
FOO(Constants.FOO_STR),
BAR(Constants.BAR_STR);
}
This code should work but also smells fishy.
Since an enum has an immutable flavor by design, I would not recommend this approach. I feel bad about posting this... but if your main problem is the resource heavy loading of these constants, maybe you do not need an enum to store those properties. Maybe just think of a simple singleton container with simple (named) properties.

Kotlin: does it make sense a property with private get and public set?

I am new to Kotlin, and I have been experimenting with the language. In Kotlin in Action, it says the following:
The accessor’s visibility by default is the same as the property’s. But you can change
this if you need to, by putting a visibility modifier before the get or set keyword.
I have tried to create a property that has a private getter and a public setter, as follows:
class BackingField {
var aProperty = 1
private get
set(value) {
field = value + 1
}
}
However, IntelliJ is suggesting me to remove the private modifier before get. Is is possible to have a public property with a private getter and a public setter? If so, what are some common applications of such entity? If not, could we conclude that what is stated in the book is partially wrong?
The book is not wrong per se. Because you can actually change the visibility on both the get and set but the set can't be more visible than the get according to this question:
Private getter and public setter for a Kotlin property
Remember that books and IDEs offer recomendations and not good design based on what you do.
The set can't be more visible than the get, as other said, but then remember that properties and backing fields is just an abstraction. You can have no backing field and declare your interface setter and getter methods with the access restrictions you wish for.
Given this use case, it's obvious that you have special requirements. I.e. the data is not just set, but also incremented by 1. So your external interface would probably have another name for it as well.
Having the syntac object.field = x invoke a setter function is suspect as well, cause the syntax implies no function invocation, as in java or C/C++ structs. it can bite you horribly and make you miss the fact that the assignment invokes a setter somewhere in your code - I would consider it bad design.
The feature of properties and getters/setters works mostly if you are working with data objects and pokos (plain old kotlin objects) only. It's very good for those cases, and can save you time, but once you stray off into more complex scenarios, as you are doing, it's weakness will begin to show.
In this case you don't need a setter, because the class will have access to it privately. The getter though, is something you have to define, and perhaps give a more apropriate name, like setAndIncrement.
class BackingField {
private var aProperty = 1
fun setAProperty(value:Int) { aProperty=value+1}
private fun getAProperty():Int { return aProperty }
fun print() {println(aProperty)}
}
fun main() {
var f = BackingField()
f.print()
f.setAProperty(10)
f.print()
println(f.aProperty) // Won't compile
}

Refer to nested objects without full qualification

I have code (all of which I control) that looks like the following:
class FirstVeryLongName {
object ObjectA
object ObjectB
object ObjectC
}
class SecondVeryLongName {
object ObjectB
object ObjectD
}
The code I need to write is equivalent to
operation1(FirstVeryLongName.ObjectA, FirstVeryLongName.ObjectB)
operation2(SecondVeryLongName.ObjectB, SecondVeryLongName.ObjectD)
...except that the repeated uses of the very long names add a lot of clutter.
Here is something I hoped would work, but doesn't seem to:
FirstVeryLongName.run {
operation1(ObjectA, ObjectB)
}
...which I wasn't able to make work, even if I tried moving ObjectA and ObjectB into the companion of FirstVeryLongName and writing
FirstVeryLongName.Companion.run { ... }
...which I had hoped would give unqualified access to the objects, as it would have for a val in the companion object.
One thing I specifically want to avoid is typealiases or importing them as aliased names. I want it to be obvious without cross-references or manually looking at the imports where these are all coming from.
Is there some trick that would let me write this code and write FirstVeryLongName, ObjectA, and ObjectB each exactly once?
It makes sense to me that it isn't working the way you tried it.
The class name itself is no instance and run or with therefore doesn't apply. It's the same as just writing the package name and nothing else. This doesn't work either.
Regarding the Companion-approach, I assume you implemented the following:
class FirstVeryLongName {
companion object {
object ObjectA
object ObjectB
object ObjectC
}
}
and a usage such as:
with(FirstVeryLongName.Companion) {
operation1(ObjectA, ObjectB)
}
Actually this could work as long as you have such properties defined for the companion (this applies to functions as well). Actually that is also something you mentioned yourself. You may want to look at the generated byte code to see what an object actually corresponds to, if you didn't do it already. If you did, you can skip the rest of this paragraph ;-) Think of it as if it were just nested classes. In the example above we therefore have 3 nested classes inside the Companion-class, which is inside the FirstVeryLongName-class.
From Kotlin the access to the singleton INSTANCE-field is hidden from you. In the Kotlin code FirstVeryLongName.Companion.ObjectA can represent both, the type and the singleton instance reference. The context is relevant.
As you can't use class-names-only or part of an import-statement in run/with, you can't also simplify the access to the singleton instance in this way.
You can however do something as follows. Note: I clearly do not recommend this approach as is (I do not believe that you really need both: the object and the val). Maybe you can also use an object expression there? There is most probably an easier way to structure your code, but without appropriate context I can only guess... I may be wrong):
class FirstVeryLongName {
companion object {
val ObjectA = FirstVeryLongName.ObjectA // can you use an object expression here?
val ObjectB = FirstVeryLongName.ObjectA
val ObjectC = FirstVeryLongName.ObjectA
}
object ObjectA
object ObjectB
object ObjectC
}
Now the run/with works as you desire, but now it actually accesses the val-reference which points to the object:
with(FirstVeryLongName.Companion) {
operation1(ObjectA, ObjectB)
}
Just showing a simple example using an object expression. You may either want to have a common superclass, interface or, if you do not mind, you can even use object : Any() here:
class FirstVeryLongName {
companion object {
val ObjectA = object : interfaces.ObjectA { /* ... */ }
// ...
}
}
Usage still looks the same. Now only the signature of operation1 may differ.

'this' is not defined in this context

How can I solve the following case?
interface I
class A(i: I)
class C : I, A(this) // << --- 'this' is not defined in this context
In short, I want to pass the class instance to super class constructor.
Is it possible in Kotlin?
P.S.
All the answers are good and technically correct. But let's give a concrete example:
interface Pilot {
fun informAboutObstacle()
}
abstract class Car(private val pilot: Pilot) {
fun drive() {
while (true) {
// ....
if (haveObstacleDetected()) {
pilot.informAboutObstacle()
}
// ....
}
}
fun break() {
// stop the car
}
}
class AutopilotCar : Pilot, Car(this) { // For example, Tesla :)
override fun informAboutObstacle() {
break() // stop the car
}
}
This example don't look too contrived, and why can't I implement it with OOP-friendly language?
No, this is not possible on the JVM. this is only available after the super class has been initialized.
From
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.2.4
The instance initialization method (§2.9.1) for class myClass sees the new uninitialized object as its this argument in local variable 0. Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass.
So the bytecode instruction aload 0 to push this on the stack is forbidden before the super-class constructor is called. That's why it cannot be passed as an argument to the super-constructor.
Kotlin was born as a JVM language and aims for maximum interoperability with Java code and a minimum overhead of its language features. While Kotlin could have chosen to orchestrate object initialization in a different way, it would create problems in mixed Java-Kotlin class hierarchies and add significant overhead.
In the good tradition of OOP languages such as Java, C# or Swift, Kotlin doesn't allow you to leak the this reference before the call to superclass initialization has completed. In your special case you're just storing the reference, but in just a slightly different case the superclass code might try to use the received object, which at that point is still uninitialized.
As a specific example of why languages don't allow this, consider a case where A is a class from a library you use and this rule is not in effect. You pass this like you do and things work fine. Later you update the library to a newer version and it happens to add something as benign as i.toString() to its constructor. It has no idea it's actually calling an overridden method on itself. Your toString() implementation observes all its invariants broken, such as uninitialized vals.
This design suffers from other problems, not just the circular initialization dependency you are struggling with now. In a nutshell, the class A expects this:
But instead you create this:
The class A has a dependency on a collaborator object of type I. It doesn't expect itself as the collaborator. This may bring about all kinds of weird bugs. For example your C.toString() may delegate to super.toString() and A.toString() (A is the super of C) may call into I.toString(), resulting in a StackOverflowError.
I can't say from your question whether A is designed for extension, which would make the C : A part correct, but you should definitely disentangle A from I.

Why no stored type properties for classes in swift?

Working through The Swift Programming Language, I was surprised to see that, unlike structures and enumerations, classes do not support stored type properties.
This is a common feature of other OO languages so I assume there was a good reason they decided not to allow it. But I'm not able to guess what that reason is, especially since structures (and enumerations) have them.
Is it simply that it's early times for Swift and it just hasn't been implemented yet? Or is there a deeper reason behind language design decision?
BTW, "stored type property" is Swift terminology. In other languages these might be called class variables. Example code:
struct FooStruct {
static var storedTypeProp = "struct stored property is OK"
}
FooStruct.storedTypeProp // evaluates to "struct stored property is OK"
class FooClass {
class var computedClassProp: String { return "computed class property is OK" }
// class var storedClassProp = "class property not OK" // this won't compile
}
FooClass.computedClassProp // evaluates to "computed class property is OK"
Edit:
I now realize this limitation is trivial to work around, e.g., by using a nested structure with stored properties:
class Foo {
struct Stored {
static var prop1 = "a stored prop"
}
}
Foo.Stored.prop1 // evaluates to "a stored prop"
Foo.Stored.prop1 = "new value"
Foo.Stored.prop1 // evaluates to "new value"
That seems to preclude their being some deep inscrutable language design reason for this limitation.
Given that and the wording of the compiler message that Martin Gordon mentions, I have to conclude that this is simply something (minor) left out.
The compiler error is "Class variables not yet supported" so it seems like they just haven't implemented it yet.
Extending the OP's nested struct trick for simulating stored type properties, you can go further and make it look like a pure stored type property from outside the class.
Use a computed getter and setter pair like:
class ClassWithTypeProperty
{
struct StoredTypeProperties
{
static var aTypeProperty: String = "hello world"
}
class var aTypeProperty: String
{
get { return self.StoredTypeProperties.aTypeProperty }
set { self.StoredTypeProperties.aTypeProperty = newValue }
}
}
Then you can do:
println(ClassWithTypeProperty.aTypeProperty)
// Prints "hello world"
ClassWithTypeProperty.aTypeProperty = "goodbye cruel world"
println(ClassWithTypeProperty.aTypeProperty)
// Prints "goodbye cruel world"
“For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only."
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/cn/jEUH0.l
I think it's easy for Apple's Engineers to add stored type properties to classes, but not yet we know, maybe never in my opinion. And that's why there are labels ( static and class ) to distinguish them.
The most important reason may be it:
To avoid different objects have shared changeable variable
we know :
static let storedTypeProperty = "StringSample" // in struct or enum ...
can be replaced by
class var storedTypeProperty:String {return "StringSample" } // in class
but
static var storedTypeProperty = "StringSample"
is harder to be replaced by class phrase in class.
// I am new to Swift Programming Language actually and it's my first answer in Stack OverFlow. Glad to discuss with you. ^^