Why doesn't Hack infer nullable types? - type-inference

Any specific reason why Hack doesn't automatically infer nullable types? Instead you have to write ? explicitly. If it used inference instead, wouldn't it be able to check for null for regular PHP programs as well?
For example, this function would have type bool -> ?string:
function foo($condition) {
if ($condition) {
return null;
else {
return 'a string';
}
}

Related

Infer property type if not null

I have a function like the following:
fun getCommonItemsFrom(element: Element): List<ElementItem>? =
if (element.parent is CommonElementWrapper) element.items
else null
So let's assume that Element has a property called parent, which is of type ElementWrapper? (an interface). And this property may or may not be a concrete instance of CommonElementWrapper.
This function returns the items (that is non-nullable List<ElementItem>) of an Element, as long as the parent property is an instance of CommonElementWrapper, otherwise null will be returned.
So I can use it like this:
if (getCommonItemsFrom(element) == null) {
return
}
// At this point I can infer that `element.parent` is a `CommonElementWrapper`.
// Since the above condition was not `null`.
if (element.parent.isSomeCommonElementWrapperThing()) {
// Error: I can't use it this way without first re-checking the parent type.
// ...
}
But currently I need to double check:
if (element.parent is CommonElementWrapper &&
element.parent.isSomeCommonElementWrapperThing()) {
// ...
}
I was wondering if Kotlin has some way of after a certain function is executed it allows to infer some things from there. Something like:
#InferIfReturnIsNotNull (element.parent is CommonElementWrapper)
fun getCommonItemsFrom(element: Element): List<ElementItem>? = ...

Type comparison / match in kotlin

I use when with type cases as mentioned in the code below. It is needed for me in reflection where I check the type of the property/field and set or cast value accordingly.
In this example, Double? property type is not matching the case Double::class.java . If I change the property type to Double without ? then everything works as expected. In this case how do I solve this for nullable properties declared with ?
valueToSet = when(member?.getter?.returnType?.javaType) {
Date::class.java -> {
DateUtil.asDate(LocalDateTime.parse(value))
}
Integer::class.java -> value.toInt()
Double::class.java -> value.toDouble()
else ->value.toString();
}
javaType gives you a Type instance, not a Java Class instance. Use classifier instead and compare against the KClasses. You can get returnType directly from the KProperty without going through the getter.
valueToSet = when(member?.returnType?.classifier) {
Date::class -> {
DateUtil.asDate(LocalDateTime.parse(value))
}
Integer::class -> value.toInt()
Double::class -> value.toDouble()
else -> value.toString();
}
Double? corresponds to java.lang.Double, Double to double. Compare against both types, e.g.:
Double::class.java, java.lang.Double::class.java -> value.toDouble()
or separate if you want to treat them differently.
(The changes suggested by Tenfour04 are a good idea as well.)

Is there an elegant kotlin way of convincing the compiler that a nullable field to which I just assigned a real value can't be null anymore?

I have read that using !! should generally be avoided.
Is there a way to write the following code in a more elegant way without having to add something like obsolete null checks and duplicated or dead blocks of code?
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
return field!!
}
}
Also I don't understand why the compiler requires the !!-'pray-this-isn't-null-operator' to be satisfied in this scenario.
EDIT: Consider that it is important to me that a potential solution uses lazy initialization if the field is null!
Problem
As Enzokie already mentioned in the comments, another thread could have changed field after the null check. The compiler has no way of knowing that, so you have to tell it.
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
// another thread could have assigned null to field
return field!! // tell the compiler: I am sure that did not happen
}
}
Solution (Eager)
In you particular case it would be a good idea to use a parameter f (you could name it "field" too, but I avoided that for clarity) in the constructor (without val/var) and afterwards assign it to a property field to which you assign either f or a new instance of Thing.
This can be expressed really concise with the Elvis operator :? which takes the left hand side if not null and the right hand side of the expression otherwise. So, in the end field will be of type Thing.
class A(f: Thing?) {
val field = f ?: Thing() // inferred type Thing
}
Solution (Lazy)
Since it was mentioned by gidds, if you need to initialize field lazyly you could do it like this using delegated properties:
class A(f: Thing?) {
val field by lazy {
f ?: Thing() // inferred type Thing
}
}
The call site does not change:
val a = A(null) // field won't be initialized after this line...
a.field // ... but after this
How about this?
class A(field: Thing?) {
private lateinit var field: Thing
init {
field?.let { this.field = it }
}
fun getField(): Thing {
if (!this::field.isInitialized) {
field = Thing()
}
return field
}
}
When you define a field, you actually define a variable plus two accessor methods:
val counter: Integer = 0
It is possible to customize the accessor methods by writing this instead:
val n = 0
val counter: Integer
get() = n++
This will execute the n++ each time you access the counter field, which therefore returns different values on each access. It is uncommon and unexpected but technically possible.
Therefore the Kotlin compiler cannot assume that two accesses to the same field return the same value twice. Usually they do, but it is not guaranteed.
To work around this, you can read the field once by copying it into a local variable:
fun count() {
val counter = counter
println("The counter is $counter, and it is still $counter.")
}

What is Dart's equivalent to Kotlin's let?

Recently I've been delving into Flutter's ecosystem and Dart has proven itself a neat and simple language.
Currently, I am looking for a best practice to run methods if an optional variable is not null.
In other words, I am looking for something in Dart that is like Kotlin's let operator :
variable?.let {
doStuff();
doABitMoreStuff();
logStuff();
}
Anyone got any ideas or best practices around this?
I've looked into Dart's documentation and have found nothing that would fit my requirements.
King regards,
With the new Dart extension functions, we can define:
extension ObjectExt<T> on T {
R let<R>(R Function(T that) op) => op(this);
}
This will allow to write x.let(f) instead of f(x).
Dart's equivalent would be a null-aware cascade operator:
The Dart approach would be a to use a null-aware cascade:
SomeType? variable = ...
variable
?..doStuff()
..doABitMoreStuff()
..logStuff();
The null-aware cascade works like the normal cascade, except that if the receiver value is null, it does nothing.
You could make your own using a static function though:
typedef T LetCallback<T>(T value);
T let<T>(T value, LetCallback<T> cb) {
if (value != null) {
return cb(value);
}
}
Then used like that:
let<MyClass>(foo, (it) {
})
We can do it with Dart 2.6 or later.
extension ScopeFunctionsForObject<T extends Object> on T {
ReturnType let<ReturnType>(ReturnType operation_for(T self)) {
return operation_for(this);
}
}
usage: https://github.com/YusukeIwaki/dart-kotlin_flavor#let
The difference between x?.let{ } and if (x != null) { } in Kotlin is that the former promotes x to be non-nullable. Since Kotlin has non-nullable types, it prevents you from needing to write x!! to assert the non-nullability inside the block.
Dart doesn't have non-nullable types (yet), so that distinction isn't important in Dart.
Just use if (x != null) { ... }.
If Dart gets non-nullable types, you can be assured that the null check in the condition will also promote x to non-nullable inside the block (if x is a local variable, is not mutated inside the block, other restrictions may apply).
(EDIT: Dart now has nullable types, and x != null promotes x to non-null.)
From your other comments, it sounds like you might be wanting the Kotlin behavior of x?.run { ... } instead, which binds this to x inside the lambda block. There is no corresponding feature in Dart. You cannot override this, it's always bound to the the object that the current method was called on, even inside nested closures which captures the value of this just as they capture other variables.
Using this extension:
extension Ext on Object? {
void ifNotNull(Function() action) {
if(this != null){
action();
}
}
}
You can achieve something similar:
object.ifNotNull(() => {
// safe code
});
I guess a closure does what you want
class Foo {
var x = 42;
void bar() {
() {
print(x);
doStuff();
doABitMoreStuff();
logStuff();
}();
}
}
Even though Dart doesn't have the let like behavior as of Kotlin but we can certainly emulate it with concise and readable code. Maybe something like this:
void main() {
String str = null;
str?.isEmpty ?? Function.apply(() {
print("Hey there you cheeky null valued variable");
}, []);
}
i implemented let function with extension function like this:
extension KotlinLet on Object?{
void let(Function callback ){
if (this != null) {
callback();
}
}
Object? also(){
if (this != null) {
return this;
}
}
}
You can simply use this package kotlin_flavor: https://pub.dev/packages/kotlin_flavor/install
There is no direct equivalent, because there is no need for it in Dart. Dart is a lot more like Java and you often end up with similar solutions.
There is almost no syntactic sugar in Dart. It's supposed to be easy to learn.
Also, Dart does not enforce strict null checks, all variables are nullable, and the language is single-threaded. That's why there is no need for let. Use if instead:
if(variable != null) {
doStuff();
doABitMoreStuff();
logStuff();
}

Kotlin idiom for working with non-null object and non-blank String representation

I have a nullable property (a Java object) that knows how to convert itself to a String, and if this representation is not empty, I would like to do something with it. In Java this looks like:
MyObject obj = ...
if (obj != null) {
String representation = obj.toString();
if (!StringUtils.isBlank(representation)) {
doSomethingWith(representation);
}
}
I'm trying to find the most idiomatic way of converting this to Kotlin, and I have:
with(obj?.toString()) {
if (!isNullOrBlank()) {
doSomethingWith(representation)
}
}
But it still feels like too much work for such a simple operation. I have this feeling that combining let, when, and with I can slim this down to something a bit shorter.
The steps are:
If the object (A) is not null
If the String representation (B) of object (A) is not blank
Do something with (B)
I tried:
when(where?.toString()) {
isNullOrBlank() -> builder.append(this)
}
But (1) it fails with:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: #InlineOnly public inline fun
CharSequence?.isNullOrBlank(): Boolean defined in kotlin.text #InlineOnly public inline fun CharSequence?.isNullOrBlank(): Boolean defined in
kotlin.text
And even if it got past that, (2) it would want the exhaustive else, which I don't really care to include.
What's the "Kotlin way" here?
You can use the (since Kotlin 1.1) built-in stdlib takeIf() or takeUnless extensions, either works:
obj?.toString().takeUnless { it.isNullOrBlank() }?.let { doSomethingWith(it) }
// or
obj?.toString()?.takeIf { it.isNotBlank() }?.let { doSomethingWith(it) }
// or use a function reference
obj?.toString().takeUnless { it.isNullOrBlank() }?.let(::doSomethingWith)
For executing the action doSomethingWith() on the final value, you can use apply() to work within the context of the current object and the return is the same object, or let() to change the result of the expression, or run() to work within the context of the current object and also change the result of the expression, or also() to execute code while returning the original object.
You can also create your own extension function if you want the naming to be more meaningful, for example nullIfBlank() might be a good name:
obj?.toString().nullIfBlank()?.also { doSomethingWith(it) }
Which is defined as an extension to a nullable String:
fun String?.nullIfBlank(): String? = if (isNullOrBlank()) null else this
If we add one more extension:
fun <R> String.whenNotNullOrBlank(block: (String)->R): R? = this.nullIfBlank()?.let(block)
This allows the code to be simplified to:
obj?.toString()?.whenNotNullOrBlank { doSomethingWith(it) }
// or with a function reference
obj?.toString()?.whenNotNullOrBlank(::doSomethingWith)
You can always write extensions like this to improve readability of your code.
Note: Sometimes I used the ?. null safe accessor and other times not. This is because the predicat/lambdas of some of the functions work with nullable values, and others do not. You can design these either way you want. It's up to you!
For more information on this topic, see: Idiomatic way to deal with nullables