Single exclamation mark in Kotlin - kotlin

What does a single exclamation mark mean in Kotlin? I've seen it a few times especially when using Java APIs. But I couldn't find it in the documentation nor on StackOverflow.

They're called platform types and they mean that Kotlin doesn't know whether that value can or cannot be null and it's up to you to decide if it's nullable or not.
In a nutshell, the problem is that any reference coming from Java may be null, and Kotlin, being null-safe by design, forced the user to null-check every Java value, or use safe calls (?.) or not-null assertions (!!). Those being very handy features in the pure Kotlin world, tend to turn into a disaster when you have to use them too often in the Kotlin/Java setting.
This is why we took a radical approach and made Kotlin’s type system more relaxed when it comes to Java interop: now references coming from Java have specially marked types -- Kotlin Blog

It's the notation for platform types:
T! means "T or T?"

Platform Types
The type names or class names ending with single exclamation mark ! are called platform types in Kotlin. You find them when you are working in Kotlin with old Java code that doesn't contain nullability information.
Examples:
Nullable Information: Nullable Type
#Nullable String in Java is considered as String? by Kotlin.
Non-null Information: Non-null Type
#NotNull String in Java is considered as String by Kotlin.
No Information: Platform Type
String without annotations in Java is considered as String! by Kotlin.
How to deal with Platform Types?
You can work with a platform type either as a nullable or a non-null. The compiler will allow you to call all methods on this type. It’s your responsibility how to use them. If you know that the value can be null, you should compare it with null before you call methods on it. If you know it’s not null, you can use it directly but as in Java, you’ll get exception if your assumption about the nullability is wrong.
Note that you can't declare platform types in Kotlin code, they come only from Java code.
Inheritance and Platform Types
While overriding Java methods in Kotlin code, you have the option to declare parameters and return types as nullable or non-null. You need to choose this wisely, because if you decide to make the parameters non-null, the Kotlin compiler generates non-null assertions for these non-null parameters. And when next time you access this Kotlin code back from Java and you pass a null value, you'll get exception.
Hope that helps clearing all your doubts about Platform Types.

A Type notated with ! is called platform type, which is a type coming from Java and thus can most probably be null. It’s what the Kotlin compiler infers by default when calling Java (for the most basic cases, Java methods can be annotated to get around this). You should handle platform types as nullable types, unless you certainly know that the particular API will never return null. The compiler allows platform types to be assigned to variables of both nullable and non-null types.
Notation for Platform Types
[...]
T! means "T or T?" [...]
You could refer to platform types as "types of unknown nullability". Also important to know is that you cannot use the exclamation-marked type for your own types, it's not part of the Kotlin syntax, it's only a notation.

I use the funny interpretation to remember those things as below:
?: I dont know whether it is null or not.
!: Be careful! This might be null.
!!: Be careful, and yes I know it. This is always not null.

I've seen it a few times especially when using Java APIs
As mentioned by s1m0nw1, T! means T or T?. The next question is: what is T?? This is nicely documented at https://kotlinlang.org/docs/reference/null-safety.html. Kotlin does not allow certain elements to be null, e.g. String, unlike Java
To allow nulls, we can declare a variable as nullable string, written
String?:
var b: String? = "abc"
b = null // ok
[...]
b?.length
This returns b.length if b is not null, and null otherwise. The type of this expression is Int?.

Excerpt from Platform Types in Kotlin :
Besides explicitly specifying a type as optional (e.g. Person?), Kotlin presents us with another beast, called Platform Type, specified by putting a single exclamation mark instead (e.g. Person!). This concept has been created for compatibility reasons, when accessing code from null-unsafe platforms like Java. It is often the case that when using a Java library, many methods return SomeType!, since the Kotlin compiler cannot infer if the result is nullable or not.
For example:
(Mutable)Collection<T>!
Just means the following: "Java collection of T may be mutable or not, may be nullable or not".
Hope this helps.

Related

Why strip() is deprecated in Kotlin and what should I use instead?

For String.strip() I get warning 'strip(): String!' is deprecated. This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
Why is it? "strip" comes from Java String
What should I use?
First of all: String.strip() is a new function in Java 11. Kotlin targets JVM 6 by default, so I was unable to reproduce your issue at first, I got a compilation error. Using JVM 11 as target in Android Studio worked with your compiler warning.
Kotlin's string class (kotlin.String) is not the same as Java's string class (java.lang.String). The Kotlin type is however mapped to the Java type (quote):
Kotlin types such as List, MutableList, String, CharSequence etc. are all compiled to their java equivalents, and thus any runtime checks will not be able to distinguish between them. At compile-time, however, they are distinct types with different sets of members. In particular, the Kotlin types do not have all members that the corresponding Java types have. They have those listed in the Kotlin std lib reference, as well as a few extra JVM specific ones (such as Collection.stream())
kotlin.String does not have a .strip() function. You are just "incidentally" calling java.lang.String.strip() which happens to be there in some target JVMs but not defined in Kotlin. If you look at the kotlin.String source in your IDE you can see it is not defined there.
The reason it is not there is because it was explicitly graylisted by the Kotlin team:
Some methods in JDK classes are undesirable in Kotlin built-ins (e.g. a lot of String methods or List.sort(), because there are Kotlin analogues with better signatures already defined).
.strip() does the same thing as kotlin.String.trim(), so use that instead.
Extended Reading
Extended Reading 2
The commit which put .strip() on the graylist

How is Dart "sound null-safety" different from Kotlin null safety?

This Dart official video states that Dart's so-called "sound null safety" is better than Kotlin's null safety design, because it can optimise the code based on whether a variable is declared nullable, and other languages (I assume this refers to languages including Kotlin) have to do runtime checks to ensure null safety.
So, what extra optimization does Dart do?
How does it interoperate with legacy codebases that are not null-safe (written before null safety) while ensuring null safety?
Dart sound null safety
So, what extra optimization does Dart do?
The benefit of sound null safety in Dart is that the compiler can make use of a non-nullable type, which can elimate null checks. Therefore, the compiler will generate fewer instructions (which results in smaller binaries and faster runtime).
Example
Take the following function:
int getAge(Animal a) {
return a.age;
}
These are the instructions the compiler generated before sound null safety:
As you can see, there are explicit instructions for checking null in the compiled code.
And this is what the same function looks like compiled with sound null safety:
Now, these additional instructions are no longer needed.
Note that the actual instructions generated starting with Dart 2.12 for the example function are the following (there were further optimizations):
See Dart and the performance benefits of sound types by Vijay Menon (Engineering Lead, Dart) for reference.
Interoperability with legacy Dart code bases
How does it interoperate with legacy codebases that are not null-safe (written before null safety) while ensuring null safety?
It does not.
Well, that is not the whole truth. If you want to use Dart >=2.12.0 with any codebase that was written before Dart 2.12 (and with that before null safety), you cannot make use of sound null safety. You can, however, interoperate with these legacy codebases by passing a compiler flag that disables sound null safety. That would be --no-sound-null-safety (see my previous answer for more details).
This means that all benefits of sound null safety are lost when interacting with legacy codebases. This is also why the Dart team encourages all package authors to migrate their code to null safety.
Comparison to Kotlin
Kotlin simply does not have the additional compiler optimizations that Dart achieves with unboxed values thanks to sound null safety.
Keep in mind that Kotlin always allows interoperability with Java, which does not have any concept of null safety. I would imagine that this is a reason why Kotlin will never be able to have sound null safety in the same way that Dart code that interoperates with legacy codebases does not. That is as long as Kotlin code is compiled for the JVM with Java interoperability.
NNBD
If we are not concerned about the compiled code but only about the developer experience, Kotlin and Dart handle null safety identically. That is both languages are non-nullable by default (NNBD).
This means that when writing code in Dart 2.12+ or in Kotlin, all types are assumed to be non-nullable unless you explicitly mark them as nullable.
The only way to get a null pointer exception is by programmer error in both languages, i.e. using the bang operator ! in Dart and double bang operator in Kotlin !!, i.e. a not-null assertion by the developer.
Note that when using null assertions, additional runtime checks have to be added to the compiled code to preserve soundness in Dart. These checks always exists for Kotlin code compiled for the JVM as it is not sound to begin with.
This can also happen when interoperating with Java code when using Kotlin or interoperating with legacy code when using Dart.
There are some more edge cases, see Null safety in Kotlin and Understanding null safety in Dart for reference.
So, what extra optimization does Dart do?
The most basic kind of optimization is that when performing calculations on numeric types, compiler can treat them (internally) as primitive types of non-reference types (unboxed values).
Why is that?
Because they cannot be null and, therefore, it is not necessary to use them as data of referenced types (boxed values).
Why is that?
Because null is represented in Dart as a null constant reference.
If there is no need to refer to this constant, then why not use value types instead of reference type? At least in the generated code, which can be optimized already at compile time.
All this thanks to the so-called "strong mode".
The strong mode in conjunction with non-nullable types allows you to optimize the code already at the compilation stage, which is very important for modes such as AOT, which do not allow code to be optimized at runtime, because it is in the RE (read and execute) mode.
How does it interoperate with legacy codebases that null-safety is not supported while ensuring null safety?
It seems to me that you should ask this as a separate question.

How do we determine a language is dynamic or static? an example is Swift

I have been reading some posts and it always get me confused.
1, some says a language is static/dynamic by how the type is determined, in runtime or in compile time. But should we say the language is static/dynamic typing language rather than static/dynamic language?
2, in some comparison of swift vs objective-c. We know that objective-c uses its runtime to do dynamic method dispatch. And some uses this as a reason to say that the language/objective-c is dynamic, is this true?!
3, I'm sometimes confused about the OOP's polymorphism, some says in order to make it work, the language HAS to support method dynamic dispatching. Is this right?
4, for swift, I know it's a static typing language, but is it a static or dynamic method dispatching language? and is it a static or dynamic language overall??
I've never heard of the term "static language" or "dynamic language." The usual terms I've heard of are "statically typed language" or "dynamically typed language."
"Dynamic" isn't a defined term in this context, so there's not much to say here.
Polymorphism has multiple different meanings, so I'll assume you mean subtype polymorphism. In that case, yes, dynamic dispatch is necessary. The whole idea is that you want objects of different types to behave in their own way in response to the same message (method call). The only way to do this is to decouple messages and function invocations, so that an appropriate function can be called at runtime depending on the type of the receiver of the message.
Swift is a statically typed language, through and through. This might be obscured a bit by type inference. If you have an expression like
func someFunction() -> Int { return 123 }
let x = someFunction()
The type inference doesn't mean "x has some type that will be figured out at runtime." To the contrary, it means "The type of x can be deduced at runtime because we already know the type of someFunction."
All types in Swift are known at compile time. In the worst case, a must at least have type Any, which is still a type. It's not a particularly useful type (because there isn't much an Any is guaranteed to be able to do), but it's still a type.
There is some confusion in that there's talk of types at compile time and runtime types. Here's an example:
class Car {
func vroom() { print("vroom") }
}
class SportsCar: Car {
override func vroom() { print("VROOOOOM") }
}
let car: Car = SportsCar()
func driveSportsCar(_: SportsCar) { print("driving") }
// Compile types are what determine usage compatibility
driveSportsCar(car) // 💥 cannot convert value of type 'Car' to expected argument type 'SportsCar'
// Runtime types are what determine method implementations
car.vroom() // => "VROOOOOM"
In this example, car has a compile time type of Car, and a runtime type of SportsCar. The compile time type determines how it can be used, where it can be passed, etc. For example, you couldn't pass car to a driveSportsCar() function, because even though its runtime type is SportsCar, its compile time type is Car, which isn't compatible.
The runtime type of an object is what determines the method implementations to be called.
Swift is a statically ‘typed’ language which means that It performs type checks before run-time.
Swift uses direct dispatch, table dispatch with its witness table, or message dispatch (obj-c ) depending on various situations, you can take a look at this article: https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/ some of the examples are outdated but the concepts will be made more clear
Static dispatch doesn’t support polymorphism because it needs to know which implementation for a method will be executed at compile time.
Hope this helps a bit.

Is it a good practice to use Nothing in generics?

Like in this example:
sealed class Option<T>
object None : Option<Nothing>() // <-- like this
class Some<T> : Option<T>()
Or, if it's not a good practice, what should I use here instead?
Are there any official response/article on that? Or is there any argumentation that this is a good practice?
I know that Nothing was designed to be used as a type for return value for functions that never returns any value, so I'm not sure if using it as a generic parameter is a valid use.
I know there is an article that says that you can do that, but I'm not sure if I can trust it.
And the author of koptional uses it too, but I don't know if I can trust that either.
Also, it looks like in Scala Option is implemented similar to that, None have type Option[Nothing] and Scala's Nothing is similar to Kotlin's Nothing.
I agree with #zsmb13's comment. Using Nothing in a generic type hierarchy is perfectly valid and even gives benefits over other options:
First, Nothing is embedded in the Kotlin type system as a subtype of any other type, so it plays well with generics variance. For example, Option<Nothing> can be passed where Option<out Foo> is expected.
Second, the compiler will perform control flow checks and detect unreachable code after a Nothing-returning member call when the type is statically known.
See also: A Whirlwind Tour of the Kotlin Type Hierarchy

Why does not Intellij follow the kotlin syntax in the null safety part of type hint?

Simple example
Intellij uses ! in NotNull type's type hint.
However, it is against the kotlin syntax. Why does Intellij ignore the syntax of kotlin that they created?
It's because LocalDate belongs to Java API, not to Kotlin, and now is not annotated with #NotNull or one of the other supported annotations (here's the complete list).
Because of that, Kotlin doesn't know if the returned value might (not) be null, so it marks the type with ! (as described here).
In the second example, you "force" the type to be not-nullable (as described here), but this will cause an exception to be thrown if the real value is actually null.