fun main()
{
println(A() == B())
}
open class A
open class B
Why the сompiler doesn't show an error on equals? If the classes are not open, there is an error Operator '==' cannot be applied to 'A' and 'B'.
(Based on my understanding of https://discuss.kotlinlang.org/t/strange-behavior-with-equality-checking/7289/2)
For classes, calling x == y is equal to calling x.equals(y). By default, equals() is a reference equality: each object is only equal to itself.
Now, consider the cases:
If both classes are not open, then their equals() can't change. Therefore, the result of comparison is always false. Since it's likely an unintended behavior, the compiler shows an error.
If exactly one class is open, then its subclasses can override its equals() behavior.
One may think that now the condition x == y may potentially become true. However, equality must satisfy some properties, and one of them is symmetry: result of x == y must be the same as y == x. Since the second class can't override its equals() behavior, the condition is still always false.
If both classes are open, then both their subclasses may override equals() so that it becomes true without violating any properties of equals().
Related
The primary target of this question is understanding the implementation and why it is like this. A solution or workaround for it would of course also be highly appreciated...
Given this example:
enum class SomeEnum(val customProp: String) {
FOO("fooProp"),
BAR("barProp");
}
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.SOURCE)
annotation class TheAnnotation(
val targetValue: String
)
#TheAnnotation(targetValue = SomeEnum.FOO.customProp)
fun testFun() {
}
The compilation results in the following error:
SomeEnum.kt: (14, 30): An annotation argument must be a compile-time constant
For obvious reasons, annotation values (along with others) must be compile-time constants, which makes sense in many different ways. What is unclear to me, is why customProp is not treated as a constant by the compiler.
If enums are defined as finite, closed sets of information, they should, in my understanding, only be mutable at compile-time a.k.a. "compile-time constant". For the unlikely case that enums somehow are modifiable at runtime in Kotlin, that would answer the question as well.
Addendum:
The enum value (e.g. SomeEnum.FOO) is actually treated as a compile-time constant. The proof is, that the following slightly changed snippet compiles:
enum class SomeEnum(val customProp: String) {
FOO("fooProp"),
BAR("barProp");
}
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.SOURCE)
#MustBeDocumented
annotation class TheAnnotation(
val targetValue: SomeEnum
)
#TheAnnotation(targetValue = SomeEnum.FOO)
fun testFun() {
}
enums are defined as finite, closed sets of information, they should, in my understanding, only be mutable at compile-time
Actually, no. An enum class is just a special kind of class, that doesn't allow you to create any new instances other than the ones that you name in the declaration, plus a bunch more syntactic sugars. Therefore, like a regular class, it can have properties whose values are only known at runtime, and properties that are mutable (though this is usually a very bad idea).
For example:
enum class Foo {
A, B;
val foo = System.currentTimeMillis() // you can't know this at compile time!
}
This basically de-sugars into:
class Foo private constructor(){
val foo = System.currentTimeMillis()
companion object {
val A = Foo()
val B = Foo()
}
}
(The actual generated code has a bit more things than this, but this is enough to illustrate my point)
A and B are just two (and the only two) instances of Foo. It should be obvious that Foo.A is not a compile time constant*, let alone Foo.A.foo. You could add an init block in Foo to run arbitrary code. You could even make foo a var, allowing you to do hideous things such as:
Foo.A.foo = 1
// now every other code that uses Foo.A.foo will see "1" as its value
You might also wonder why they didn't implement a more restricted enum that doesn't allow you to do these things, and is a compile time constant, but that is a different question.
See also: The language spec
* Though you can still pass Foo.A to an annotation. To an annotation, Foo.A is a compile time constant, because all the annotation has to do, is to store the name "Foo.A", not the object that it refers to, which has to be computed at runtime.
I learned to program with Kotlin a few months ago, and I wrote a bunch of code with it.
Recently, as I was working on a personal project, I tried something like that :
1 | sealed class Base(derivedRef: Any) {
2 |
3 | init {
4 | println("$derivedRef shouldn't be null !")
5 | }
6 |
7 | object Derived: Base(Derived)
8 | }
9 |
10| fun main() {
11| val neededToInitializeDerived = Base.Derived
12| }
At compile time, no problem: all seems to work as it should, and my IDE (Idea Intellij) doesn't highlight any part of my code in red. But, once compiled, if I try to run it, it prints a weird result :
null shouldn't be null !
After thinking a bit, it appears that derivedRef, typed as Any - and also not-null, thanks to the null safety - is, actually, null.
My theory is that when I'm passing the Derived object itself as a parameter of its own superclass constructor (and in fact the singleton instance of the Derived class, once compiled, through Derived.INSTANCE), Derived.INSTANCE isn't instantiated since the class Derived itself and its superclass Base aren't. It takes also a provisory null value, normally hidden at compile time and no more available at runtime, but that I successfully capture with this specific code snippet.
The problem is that I now have a null value instead of the normal Any one, throwing a NullPointerException as soon as I call a method needing a non-null Any value with it; I have some fun while doing impossible things using this glitch, but I think that it can be dangerous since it won't crash at runtime, letting you run your code free until the said method is called and making your program throw an unexpected error where the compiler ensures you "Don't worry, all is fine right there".
After proceeding to some tests, the bug has further consequences : I'm now able to put null values inside a MutableList<Any> :
val theForbiddenValue: Any // Let's say it's actually null
val myList = mutableListOf<Any>()
myList.add(null) // Normal, won't compile
myList.add(theForbiddenValue) // Compiles ! If I print it, I obtain "[null]" !
And to do other weird things that shouldn't happen at all, such as defining functions supposed to return Any but do not, etc. My last thought - I promise -, by making Base implements List<Any> for example, Derived will also implement it. And thus you can change the type of derivedRef from Any to List<Any>, and also obtain a null value where List<Any> is expected. This also works with every interface and/or non-final class.
So my question is, is it a real bug that I just discovered ? Or is it already known by many developers ? Or is it normal despite the appearances (I will be really surprised in that case) ??
This is about the order of construction — though it's much more subtle than most.
The most common order-of-construction issue is that in general, a constructor shouldn't refer to anything in the class that could be overridden (or changed) by a subclass.
In Java and Kotlin, a constructor always calls the superclass constructor as the very first thing it does. (If you don't write an explicit call, the compiler inserts one for you.) After that returns, it runs any field initialisers, and then the rest of the constructor. So when the superclass constructor runs, none of the subclass initialisers or constructor code have been run yet. This means that non-primitive fields will be null at that point — even if they're of a non-nullable type.
(I'm guessing that this isn't made a compile-time error because there might be circumstances in which it's perfectly fine: for example, if a subclass overrides a superclass method but doesn't refer to any fields which are overridden or set in the subclass constructor. Note that the IDE shows a warning, such as "Accessing non-final property […] in constructor" or "Calling non-final function […] in constructor".)
What's happening in this case, however, is much less obvious, because of the combination of a sealed class and an object subclass. As far as I can tell, the order of events is:
Because main() refers to Derived, it will construct the Derived object.
The first thing that Derived's constructor does is to call the superclass constructor, passing a reference to itself. However, because the object hasn't yet been constructed, its reference seems to be null. ← This is of course the cause of the bug, and ideally would give a compile-time error, or at least a warning.
The superclass constructor runs, and prints out the message you see.
The rest of the subclass constructor runs (and does nothing). By this point, Derived gives a valid references, but by then it's too late.
The rest of the main() method runs, setting its local variable.
Here's a variation which illustrates the order a little better. (I've moved the object outside the sealed class, though that makes no practical difference. I've also made derivedRef a property, so we can see it afterward.)
sealed class Base(val derivedRef: Any) {
init {
println("Base.init: Derived = $Derived, derivedRef = $derivedRef")
}
}
object Derived: Base(Derived) {
init {
println("Derived.init: Derived = $Derived, derivedRef = $derivedRef")
}
}
fun main() {
println("main: Derived = $Derived, derivedRef = ${Derived.derivedRef}")
}
This prints something like:
Base.init: Derived = null, derivedRef = null
Derived.init: Derived = Derived#87aac27, derivedRef = null
main: Derived = Derived#87aac27, derivedRef = null
You can see that the Derived reference is valid once the superclass constructor has finished, even before its own constructor has finished; but of course that's too late for the property, which has already been set to null.
By the way, this doesn't happen if the object is made into a normal class: it would have to pass this when it calls the superclass constructor, but the compiler complains that "'this' is not defined in this context".
Alternatively, if the sealed class is made into a plain open class, then it compiles OK but gives a NullPointerException at runtime.
So it's the combination of sealed class and object subclass that leads to this particular issue. Presumably the compiler can't spot that the object reference isn't valid yet (like it does for an explicit this in the case of a simple subclass).
Why this code can be compiled and executed without erros?
val map = HashMap<Int, Long>()
val key :Int? = null
map.remove(key)
In MutableMap remove declared as accepting only non nullable key, so it shouldn't even compile. Is it a Kotlin type inference bug or am I missing something?
public fun remove(key: K): V?
Your code is perfectly fine as remove() allows nullable arguments - your map contents definition got nothing to it. When remove() is invoked, it would try to find matching requested key in the map and as it's not there (it's completely irrelevant why it's not there - it's valid case for key to be not present) nothing will happen. Where compiler will complain is on any attempt to put such key into your map. Then map definition kicks in and since it's known that nullable keys not allowed, such code won't even compile as this is clearly buggy code.
In this case, map.remove(key) doesn't not calls
public fun remove(key: K): V?
It calls an extension remove function:
public inline fun <#OnlyInputTypes K, V> MutableMap<out K, V>.remove(key: K): V? =
#Suppress("UNCHECKED_CAST") (this as MutableMap<K, V>).remove(key)
This function documentation says that it allows to overcome type-safety restriction of remove that requires to pass a key of type K.
It allows overcoming type-safety restriction because the key of the entry you are removing does not have to be the same type as the object that you pass into remove(key); the specification of the method only requires that they be equal. This follows from how the equals() method takes in an Any as a parameter, not just the same type as the object.
Although it may be commonly true that many classes have equals() defined so that its objects can only be equal to objects of its own class, there are many places where this is not the case. For example, the specification for List.equals() says that two List objects are equal if they are both Lists and have the same contents, even if they are different implementations of List. So, for example, according to the specification of the method, it is possible to have a MutableMap<ArrayList<Something>, Something> and call remove(key) with a LinkedList as an argument, and it should retrieve the key which is a list with the same contents. This would not be possible if this extension remove(key) didn't exist.[1]
Kotlin could warn or refuse to compile (would be good), but it doesn't (for now).
The reason for it being not as bad as it looks from a first glance is that you cannot put an Int? into a MutableMap<Int, Long> because
val map = HashMap<Int, Long>()
val key :Int? = null
map.put(key, 1) // <--- WON'T COMPILE [Type mismatch: inferred type was Int? but Int was expected]
map.remove(key)
Nevertheless, I think you are right by wondering about that method being compiled.
Eventually asking this question helped to find another question with explanation. In short, what actually happens is call of the extension function which have it's own type inference.
What is the difference between referential equality and structural equality
in Kotlin?
val a = File("/myfile.txt")
val b = File("/myfile.txt")
val sameRef = a === b
and:
val a = File("/myfile.txt")
val b = File("/myfile.txt")
val both= a == b
Referential equality === (also called identity) means that the pointers for two objects are the same. That is to say the objects are contained in the same memory location which leads us to the fact that pointers reference to the same object.
identity: determines whether two objects share the same memory address
Structural equality ==, in its turn, means that two objects have equivalent content. You should specify when two objects should be considered equal by overriding the equals() method.
equality: determines if two object contain the same state.
As well as in Java, in Kotlin there're no specific equals() and hashCode() generated by default (not considering data classes). Thus, until you've overriden these methods for your class, both == and === perform identity comparison.
Object slicing is some thing that object looses some of its attributes or functions when a child class is assigned to base class.
Some thing like
Class A{
}
Class B extends A{
}
Class SomeClass{
A a = new A();
B b = new B();
// Some where if might happen like this */
a = b; (Object slicing happens)
}
Do we say Object slicing is any beneficial in any ways?
If yes, can any one please tell me how object slicing be a helpful in development and where it might be helpful?
In C++, you should think of an object slice as a conversion from the derived type to the base type[*]. A brand new object is created, which is "inspired by a true story".
Sometimes this is something that you would want to do, but the result is not in any sense the same object as the original. When object slicing goes wrong is when people aren't paying attention, and think it is the same object or a copy of it.
It's normally not beneficial. In fact it's normally done accidentally when someone passes by value when they meant to pass by reference.
It's quite hard to come up with an example of when slicing is definitively the right thing to do, because it's quite hard (especially in C++) to come up with an example where a non-abstract base class is definitively the right thing to do. This is an important design point, and not one to pass over lightly - if you find yourself slicing an object, either deliberately or accidentally, quite likely your object hierarchy is wrong to start with. Either the base class shouldn't be used as a base class, or else it should have at least one pure virtual function and hence not be sliceable or passable by value.
So, any example I gave where an object is converted to an object of its base class, would rightly provoke the objection, "hang on a minute, what are you doing inheriting from a concrete class in the first place?". If slicing is accidental then it's probably a bug, and if it's deliberate then it's probably "code smell".
But the answer might be "yes, OK, this shouldn't really be how things are structured, but given that they are structured that way, I need to convert from the derived class to the base class, and that by definition is a slice". In that spirit, here's an example:
struct Soldier {
string name;
string rank;
string serialNumber;
};
struct ActiveSoldier : Soldier {
string currentUnit;
ActiveSoldier *commandingOfficer; // the design errors multiply!
int yearsService;
};
template <typename InputIterator>
void takePrisoners(InputIterator first, InputIterator last) {
while (first != last) {
Soldier s(*first);
// do some stuff with name, rank and serialNumber
++first;
}
}
Now, the requirement of the takePrisoners function template is that its parameter be an iterator for a type convertible to Soldier. It doesn't have to be a derived class, and we don't directly access the members "name", etc, so takePrisoners has tried to offer the easiest possible interface to implement given the restrictions (a) should work with Soldier, and (b) should be possible to write other types that it also works with.
ActiveSoldier is one such other type. For reasons best known only to the author of that class, it has opted to publicly inherit from Soldier rather than providing an overloaded conversion operator. We can argue whether that's ever a good idea, but let's suppose we're stuck with it. Because it's a derived class, it is convertible to Soldier. That conversion is called a slice. Hence, if we call takePrisoners passing in the begin() and end() iterators for a vector of ActiveSoldiers, then we will slice them.
You could probably come up with similar examples for an OutputIterator, where the recipient only cares about the base class part of the objects being delivered, and so allows them to be sliced as they're written to the iterator.
The reason it's "code smell" is that we should consider (a) rewriting ActiveSoldier, and (b) changing Soldier so that it can be accessed using functions instead of member access, so that we can abstract that set of functions as an interface that other types can implement independently, so that takePrisoners doesn't have to convert to Soldier. Either of those would remove the need for a slice, and would have potential benefits for the ease with which our code can be extended in future.
[*] because it is one. The last two lines below are doing the same thing:
struct A {
int value;
A(int v) : value(v) {}
};
struct B : A {
int quantity;
B(int v, int q) : A(v), quantity(q) {}
};
int main() {
int i = 12; // an integer
B b(12, 3); // an instance of B
A a1 = b; // (1) convert B to A, also known as "slicing"
A a2 = i; // (2) convert int to A, not known as "slicing"
}
The only difference is that (1) calls A's copy constructor (that the compiler provides even though the code doesn't), whereas (2) calls A's int constructor.
As someone else said, Java doesn't do object slicing. If the code you provide were turned into Java, then no kind of object slicing would happen. Java variables are references, not objects, so the postcondition of a = b is just that the variable "a" refers to the same object as the variable "b" - changes via one reference can be seen via the other reference, and so on. They just refer to it by a different type, which is part of polymorphism. A typical analogy for this is that I might think of a person as "my brother"[**], and someone else might think of the same person as "my vicar". Same object, different interface.
You can get the Java-like effect in C++ using pointers or references:
B b(24,7);
A *a3 = &b; // No slicing - a3 is a pointer to the object b
A &a4 = b; // No slicing - a4 is a reference to (pseudonym for) the object b
[**] In point of fact, my brother is not a vicar.