As we know, the value of a global variable can be modified by other threads at any time. However why can ?.let in kotlin prevent an NPE in multithreading? For example:
var demo : Demo? = null
demo = Demo()
Thread{
demo?.let {
while (true){
it.run()
Thread.sleep(300)
}
}
}.start()
Thread.sleep(3000)
demo = null
In the above programme, the child thread can be executed normally, though the main thread has set the variable demo to null.
So, why can't the 'it' in the construction of 'let' be influenced by other thread? Is it a deep copy of the Object 'demo'?
So, why the 'it' in the construction of 'let' can not be influenced by other thread?
.let { } has really nothing magical. It's a very simple function. When you write demo?.let { println(it) }, the code is effectively equivalent to:
val it = demo
if (it != null) {
println(it)
}
So as you can see, a new variable is created and set to the value of demo. Therefore, if other threads modify demo, it is not affected.
It's a deep copy of the Object 'demo'?
It's really not a deep copy: if a thread mutates the properties of the Demo instance, they will be visible by any code that accesses that instance*, even through the it variable.
However, you don't need a deep copy for this code to work fine. demo is a reference variable that initially points to the Demo() instance created at the beginning of the code.
When we do val it = demo (from the code equivalent to ?.let), we copy the current value of the demo variable into it, and that value is the reference to the Demo instance. We say that it "points to" the same Demo instance as demo.
When the other thread sets demo to null, it doesn't change anything in the Demo instance. This has the effect that, now, demo doesn't point anymore to the initial Demo instance. But it still points to it.
(*although there are some subtleties here, like happen-before relationships, volatile variables etc., but let's not complicate things)
Another supplementary point to help with your understanding.
There is no concept of a class instance becoming null. If you are working with an instance, it exists and it is not null.
References can become null. You can have multiple references to the same instance. As long as there exists somewhere at least one reference to a class instance, that class instance still exists, even if some of the references that used to point to it are now pointing at something else, such as null.
If you do this, you are not copying your class instance, and definitely not deep-copying it! You are only copying the reference.
val item = demo
If demo is changed to point at null, that has no effect on the instance of Demo itself, and item is still pointing at that same, unchanged instance.
Since .let internally copies a reference in the same way, it is preserving that reference even if the demo property is changed to point at something else or null.
It's not a deep copy. It's literally the object that it was before. What you need to realize is that variables are just pointers to objects. Say you have
var demo : Demo? = Demo()
var demo2 : Demo? = demo
var demo3 : Demo? = demo
var demo4 : Demo? = demo
you have 4 variables pointing to the same object. If you do
demo = null
after these 4 lines then you merely make that variable no longer point to that object. demo2, demo3 and demo4 still will point to the object that you assigned to demo in the beginning. The same happens in the let block where it is just another variable that was assigned the same object in the beginning of the block so that any assignments to the original demo won't have effect on it
Related
class Notification(val context: Context, title: String, message: String) {
private val channelID = "TestMessages"
companion object ID {
var s_notificationID = -1
}
init {
var notificationID = -1
synchronized(s_notificationID) {
if (++s_notificationID == 0)
createNotificationChannel()
notificationID = s_notificationID
}
The above is being called simultaneously from two threads. A breakpoint in createNotificationChannel() clearly showed that sometimes s_notificationID equals 1.
However, if I change
synchronized(s_notificationID)
to synchronized(ID)
then it seems to lock fine.
Is synchronized() not locking basic types? And if so, why does it compile?
A look at the generated JVM bytecode indicates that the ID example looks like
synchronized(ID) { ... }
which is what you'd expect. However, the s_notificationID example looks more like
synchronized(Integer.valueOf(s_notificationID)) { ... }
In Java, we can only synchronize on objects, not on primitives. Kotlin mostly removes this distinction, but it looks like you've found one place where the implementation still seeps through. Since s_notificationID is an int as far as the JVM is concerned (hence, not an object) but synchronized expects an object, Kotlin is "smart" enough to wrap the value in Integer.valueOf on demand. Unfortunately for you, that produces wildly inconsistent results, because
This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
So for small numbers, this is guaranteed to lock on some cached object in memory that you don't control. For large ones, it may be a fresh object (hence always unlocked) or it might again end up on a cached object out of your hands.
The lesson here, it seems, is: Don't synchronize on primitive types.
Silvio Mayolo explained why it is not a good idea to synchronize on primitives (actually, I think the compiler should warn about this). But I believe there is another problem with this code, probably the main one that makes your synchronized blocks work in parallel.
The problem is that you replace the value of s_notificationID. Even if it would be an object, not a primitive, your synchronized blocks would still run in parallel, because each call to synchronized uses a different object. This is why in Java we usually synchronize on this and not on a field that we need to modify.
TL;DR The lesson here, it seems, is: Don't synchronize on primitive types.
synchronized(i) where i is Int, is actually synchronized(Integer.valueOf(i)).
Only in the range -128 to 127 this value is guaranteed to be a cached value.
Another fact is that ++i cannot be looked at as a mutation of the "object" i, but rather as replacing i by a new "object" with the value i+1.
Thank you broot & Silvio Mayolo for the above.
Experiments I did prove the above.
In my original code I have removed the ++ from
++s_notificationID. Amazingly or not, the lock worked now.
Now with that change I changed var s_notificationID = -1 to be var s_notificationID = -1000. Even more amazing, now the lock again stopped working.
Still, I think this anomaly of basic types undermines the attempt of Kotlin to see basic types as objects, and I think this should have been mentioned clearly in Kotlin documentation.
According to the Kotlin docs, the ?. operator represents a 'safe call', meaning that if it's used in a chain of method calls, the entire chain will return null if the value of whatever it's used on is null.
But what about if it's used on the left side of an assignment? Since the left side isn't the side that's 'returning' anything it seems like it probably has a different effect. Here's an example of what I'm talking about:
val myObj = SomeObj()
myObj?.property = SomeClass.someFunc() // What does ?. do in this context?
It means that if one of the safe calls on the left-hand side fails (i.e. its receiver is null), then the whole assignment is skipped, and the expression on the right-hand side is not evaluated at all.
val nullable: Container? = null
nullable?.x = f() // f is not called
(runnable demo)
I'm seeing a fun question & answer in Kotlin just now. Even if the answer is very nice, but I want to clarify it in more detailed.
The assignment expression below:
myObj?.property = SomeClass.someFunc()
is transformed to Java bytecode by Kolin as below:
val it = myObj;
if(it != null){
it.property = SomeClass.someFunc();
}
so there is no problem in multiple threads. It still works fine and I have tested it on github. But it will result in the Thread Interference problem, which means it will modify the property on different references when myObj is changed.
Except the assignment expression can be short-circuited, others also can be short-circuited. For example:
val array:Array<Any>? = null;
// v--- short-circuited
array?.set(0,SomeClass.someFunc());
// ^--- never be called
According to the Kotlin docs, the ?. operator represents a 'safe call', meaning that if it's used in a chain of method calls, the entire chain will return null if the value of whatever it's used on is null.
But what about if it's used on the left side of an assignment? Since the left side isn't the side that's 'returning' anything it seems like it probably has a different effect. Here's an example of what I'm talking about:
val myObj = SomeObj()
myObj?.property = SomeClass.someFunc() // What does ?. do in this context?
It means that if one of the safe calls on the left-hand side fails (i.e. its receiver is null), then the whole assignment is skipped, and the expression on the right-hand side is not evaluated at all.
val nullable: Container? = null
nullable?.x = f() // f is not called
(runnable demo)
I'm seeing a fun question & answer in Kotlin just now. Even if the answer is very nice, but I want to clarify it in more detailed.
The assignment expression below:
myObj?.property = SomeClass.someFunc()
is transformed to Java bytecode by Kolin as below:
val it = myObj;
if(it != null){
it.property = SomeClass.someFunc();
}
so there is no problem in multiple threads. It still works fine and I have tested it on github. But it will result in the Thread Interference problem, which means it will modify the property on different references when myObj is changed.
Except the assignment expression can be short-circuited, others also can be short-circuited. For example:
val array:Array<Any>? = null;
// v--- short-circuited
array?.set(0,SomeClass.someFunc());
// ^--- never be called
code sample:
//...
CloseableIterator<Order> iterator = dao.iterator();
iterator.first(); // Object
iterator.current(); // Object
iterator.hasNext(); // false (only 1 record in table "Order")
iterator.current(); // null (?!)
iterator.first(); // null (?!!)
Also, iterator.previous() returns null too (if more than 1 record, ofc).
How to forbid ORMLite's SelectIterator to forget my data after calling hasNext() on the last record?..
According to the source code of ORMLite, it is a normal undocumented unchangeable behavior.
Just ran into this myself. We're using ORMLite on Android and were able to use methods available on the DatabaseResults member, available by calling:
iterator.getRawResults()
You'll have to cast it to the appropriate type before being able to do things like safely check count etc. (depending on whether or not they are available in your particular implementation)
I've not been using C++ for about 4 years and came back to it a month ago, and that was where I also have first heard about the CLI extension. I still have to get used to it, but this website helps a lot! Thank you!! Anyway, I couldn't find an answer to the following problem:
When I declare a variable
int iStack;
then it is declared but not defined, so it can have any value like
iStack = -858993460
depending on what the value at the stack position is, where the variable is created.
But when I declare a variable on the heap
int^ iHeap
then as far as I know the handle is created but the variable is not instantiated (don't know if you call it instantiation here) or defined and I can only see
iHeap = <Nicht definierter Wert> (which means <undefined value>)
Is there any way to detect if this value is defined?I particularly don't need it for int, but for example for
array<array<c_LocationRef^,2>^>^ arrTest2D_1D = gcnew array<array<c_LocationRef^,2>^>(2);
to find out if the elements of the outer or inner array are instantiated (I'm sure here it is an instantiation ;-) )
arrTest2D_1D = {Length=2}
[0] = {Length=20}
[1] = <Nicht definierter Wert> (=<undefined value>)
As far as I know, the CLR automatically initialise your variables and references in C++ CLI.
In .NET, the Common Language Runtime (CLR) expressly initializes all
variables as soon as they are created. Value types are initialized to
0 and reference types are initialized to null.
To detect if your variable is initialised, you should compare the value of your hat variable to nullptr :
int^ iHeap;
if(iHeap == nullptr){
Console::WriteLine(L"iHeap not initialised");
}
This works on my VS2010 ; it outputs iHeap not initialised
It should work for your specific problem as well (arrays).
By the way, value types are initialised to zero hence your first example should output 0 (I've tested it, and it does output 0) :
int iStack;
Console::WriteLine(L"iStrack = {0}", iStack); // outputs 0
Quote is from codeproject
MSDN page for nullptr
EDIT: Here is an other quote, from Microsoft this time :
When you declare a handle it is automatically initialized with null, so it will not refer to anything.
Quote from MSDN see the paragraph "Tracking Handles"