Unsafe assignment of any value trying to transform properties on an object - typescript-eslint

I have something like this snippet:
function transformIt(value: any): any {
...
}
let foo: any = ...
if (typeof foo === 'object') {
for (const property in value) {
foo[property] = transformIt(foo[property])
}
}
When I run eslint on this, it complains that there's an unsafe assignment of an any value but I can't figure out how to make it happy. Would appreciate any insight on this.

How to check if type has index signature at runtime has the answer. Thought I tried that on my own, but seems to work now.
function hasIndexSignature(v: any): v is {[index: string]: any} {
return typeof v === 'object'
}
let foo: any = ...
if (hasIndexSignature(foo)) {
for (const property in value) {
foo[property] = transformIt(foo[property])
}
}

Related

why Kotlin inline function params is must not be null

inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: (() -> Unit)? = null) {
if (value != null) {
notNullBlock(value)
} else {
if(isNullBlock != null){
isNullBlock()
}
}
}
I tried to write some higher-order functions to facilitate development, but it is error
I think it is related to how inline functions and lambdas passed to it are inlined. The inline modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site. It seems Kotlin doesn't allow to use nullable lambdas.
If you want some default value for isNullBlock parameter you can use empty braces isNullBlock: () -> Unit = {}:
inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: () -> Unit = {}) {
if (value != null) {
notNullBlock(value)
} else {
isNullBlock()
}
}
There is a great post explaining how inline works from Android Developer Advocate Florina Muntenescu. Following all of the explanations it should be clear why nullable lambdas are not allowed.
In short:
Because of the inline keyword, the compiler copies the content of the inline function to the call site, avoiding creating a new Function object.
That is the performance benefit inline keyword gives us. But in order to do that compiler must be sure that you always pass in a lambda argument whether it is empty or not. When you try to make the lambda argument nullable compiler will not be able to copy the content of a null lambda to the call site. Similarly, you cannot execute compare operations like != null or use ? to unwrap the optional lambda that should be inlined because when compiled there will be no lamda/function objects. More explanation below.
Example (long explanation)
In my examples your function is updated and takes empty lambda as default arguments for isNullBlock:
inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: (() -> Unit) = {}) {
if (value != null) {
notNullBlock(value)
} else {
isNullBlock()
}
}
Here is usage of not inlined version of your isNullObject function decompiled to Java.
Kotlin code
class Test {
init {
isNullObject(null as? Int,
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
isNullObject(0,
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
}
}
Decompiled Java code
public final class Test {
public Test() {
TestKt.isNullObject((Integer)null, (Function1)null.INSTANCE, (Function0)null.INSTANCE);
TestKt.isNullObject(0, (Function1)null.INSTANCE, (Function0)null.INSTANCE);
}
}
As you can see nothing too unusual happens (though, it is hard to understand what null.INSTANCE is). Your isNullObject function called with three arguments passed as defined in Kotlin.
Here is how your inlined function will decompile using the same Kotlin code.
public final class Test {
public Test() {
Object value$iv = (Integer)null;
int $i$f$isNullObject = false;
int var3 = false;
String var4 = "isNullBlock called";
boolean var5 = false;
System.out.println(var4);
int value$iv = false;
$i$f$isNullObject = false;
int var8 = false;
String var9 = "notNullBlock called";
boolean var6 = false;
System.out.println(var9);
}
}
For the first function call, we immediately get if (value != null) statement resolved as false and notNullBlock passed in is not even ended up in the final code. At runtime, there will be no need to check each time if the value is null or not. Because the isNullObject is inlined with its lambdas there is no Function objects generated for lambda arguments. It means there is nothing to check for nullability. Also, this is the reason why you cannot hold a reference to the lambda/function arguments of the inlined function.
Object value$iv = (Integer)null;
int $i$f$isNullObject = false;
int var3 = false;
String var4 = "isNullBlock called";
boolean var5 = false;
System.out.println(var4);
But inlining works only if compiler is able to get values of given arguments at compile time. If instead of isNullObject(null as? Int, ...) and isNullObject(0, ...) the first argument was a function call - inlining would give no benefit!
When compiler cannot resolve if statement
A function added - getValue(). Returns optional Int. The compiler does not know the result of getValue() call ahead of time as it can be calculated only at runtime. Thus inlining does only one thing - copies full content of the isNullObject into Test class constructor and does it twice, for each function call. There is a benefit still - we get rid of 4 Functions instances created at runtime to hold the content of each lambda argument.
Kotlin
class Test {
init {
isNullObject(getValue(),
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
isNullObject(getValue(),
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
}
fun getValue(): Int? {
if (System.currentTimeMillis() % 2 == 0L) {
return 0
} else {
return null
}
}
}
Decompiled Java
public Test() {
Object value$iv = this.getValue();
int $i$f$isNullObject = false;
int it;
boolean var4;
String var5;
boolean var6;
boolean var7;
String var8;
boolean var9;
if (value$iv != null) {
it = ((Number)value$iv).intValue();
var4 = false;
var5 = "notNullBlock called";
var6 = false;
System.out.println(var5);
} else {
var7 = false;
var8 = "isNullBlock called";
var9 = false;
System.out.println(var8);
}
value$iv = this.getValue();
$i$f$isNullObject = false;
if (value$iv != null) {
it = ((Number)value$iv).intValue();
var4 = false;
var5 = "notNullBlock called";
var6 = false;
System.out.println(var5);
} else {
var7 = false;
var8 = "isNullBlock called";
var9 = false;
System.out.println(var8);
}
}

Test object member for null before executing IF block

I have the following code:
class Countries {
var list: MutableList<String>? = null
}
val countries = Countries()
if (countries.list!!.isNotEmpty()) {
}
At runtime this will raise an exception because list is null. I can do this instead:
if ((countries.list != null) && countries.list!!.isNotEmpty()) {
}
If I had a boolean member called areInitialized that was nullable, I could create a infix function like this:
infix fun Any?.ifTrue(block: () -> Unit) {
if ((this != null) && this == true) block()
}
and then use it like this:
countries.areInitialized ifTrue {
}
But I can't seem to create something similar for a mutable list.
But I hate having to repeat this test for null on an member field in other parts of code. Is there a simpler way in Kotlin to do this?
I would try to stick to the standard as often as you can. So in your example I wouldn't have introduced that ifTrue-function, but rather used takeIf or takeUnless in combination with the safe operator ?. instead, e.g.:
countries?.takeIf { it.areInitialized == true }
?.also {
/* do something with countries */
}
Or if you must return a value, exchange also with let (or see the other scope functions).
The same then also works for the list within countries:
countries?.takeUnless { it.list.isNullOrEmpty() }
?.also {
/* do something with countries */
it.list!!.forEach(::println)
}

Kotlin general setter function

I am new to kotlin. I wonder if this is possible
I wish to create a function that will change the value of the properties of the object and return the object itself. The main benefit is that I can chain this setter.
class Person {
var name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
try {
// the line below caused error
this[propName] = value
} catch(e:Exception){
println(e.printStackTrace())
}
}
}
}
//usage
var person = Person(null,null)
person
.setter(name, "Baby")
.setter(age, 20)
But I get error "unknown references"
This question is marked as duplicate, however the possible duplicate question specifically want to change the property of "name", but I wish to change anyProperty that is pass from the function to object. Can't seem to connect the dot between two questions. #Moira Kindly provide answer that explain it. thankyou
Why not just simplify your answer to
fun setter(propName: String, value: Any): Person {
val property = this::class.memberProperties.find { it.name == propName }
when (property) {
is KMutableProperty<*> ->
property.setter.call(this, value)
null ->
// no such property
else ->
// immutable property
}
}
Java reflection isn't needed, its only effect is to stop non-trivial properties from being supported.
Also, if you call it operator fun set instead of fun setter, the
this[propName] = value
syntax can be used to call it.
After googling around, I think I can provide an answer, but relying on java instead of kotlin purely. It will be great if someone can provide a better answer in kotlin.
class Person(
var name: String,
val age: Int
){
fun setter(propName: String, value: Any): Person{
var isFieldExistAndNotFinal = false
try{
val field = this.javaClass.getDeclaredField(propName)
val isFieldFinal = (field.getModifiers() and java.lang.reflect.Modifier.FINAL == java.lang.reflect.Modifier.FINAL)
if(!isFieldFinal) {
// not final
isFieldExistAndNotFinal = true
}
// final variable cannot be changed
else throw ( Exception("field '$propName' is constant, in ${this.toString()}"))
} catch (e: Exception) {
// object does not have property
println("$e in ${this.toString()}")
}
if(isFieldExistAndNotFinal){
val property = this::class.memberProperties.find { it.name == propName }
if (property is KMutableProperty<*>) {
property.setter.call(this, value)
}
}
return this;
}
}
usage like this
person
.setter(propName = "age", value = 30.00)
.setter(propName = "asdf", value = "asdf")
.setter(propName = "name", value = "A Vidy")
You have error because when you do this[propName] = value you are trying to use this as a list, but it is not a list, it is a Person and it doesn't overload the [] operator.
What you can do is to add a check for the property that is setted:
class Person {
privavar name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
if (propName == "name" && value is String?) {
it.name = value as String?
} else if (propName == "age" && value is Int?) {
it.age = value as Int?
} else {
// handle unknown property or value has incorrect type
}
}
}
}
Another more dynamic solution without reflection:
class Person {
private var fields: Map<String, Any?> = HashMap()
fun setter(propName:String, value:Any): Person{
return this.apply {
it.fields[propName] = value;
}
}
fun getName() = fields["name"]
}
If you want to get rid of the getters as well then you need to use reflection.

Could not cast value of type XX to XX in swift 3

In Swift 3 contains method is always giving error. In the below code if annotation is MKAnnotation is passed and goest to next line. Then it gives error. I have searched a lot but not able to find the problem. Any solution for this issue?
Class declaration:
open class FBAnnotation : NSObject {
open var coordinate = CLLocationCoordinate2D(latitude: 52.0936440, longitude: 4.3592340)
open var title: String? = ""
open var annotationIndex: Int?
}
extension FBAnnotation : MKAnnotation {
}
Usage:
do {
if annotation is MKAnnotation {
if try node.annotations.contains(where: annotation as! (MKAnnotation) throws -> Bool) {
try node.annotations.remove(at: node.annotations.index(where: annotation as! (MKAnnotation) throws -> Bool)!)
node.count -= 1
return true
}
}
} catch {
return false
}
This works in a playground, no casting required. You cannot pass an annotation as the where parameter. You must pass in a function that declares whether or not the annotation is the one you are looking for. Here I consider them a match if they have the same coordinates, although your match criteria may be different.
var annotations = [MKAnnotation]()
var annotation: Any? = nil
if let annotation = annotation as? MKAnnotation {
if let index = annotations.index(where: {
$0.coordinate.latitude == annotation.coordinate.latitude &&
$0.coordinate.longitude == annotation.coordinate.longitude
}) {
annotations.remove(at: index)
}
}

Changing a enum's field in Rust

I am very new to Rust but I am trying to work out how to modify an instance of an enum. I need to use managed boxes for other reasons, but it seems to make changing an enum's field hard.
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let mut state = #A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
I get the error cannot borrow immutable anonymous field as mutable. The mut seems to only say that state, the variable, is mutable. I want to tell Rust the whole thing is mutable. I find forced immutability one of the most annoying things of Rust.
Some time ago managed boxed had their own "hierarchy" of mutability. The following code used to work then:
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let state = #mut A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
But managed boxes are scheduled to be removed from the language. In current version of Rust #mut is not a valid token. You have to use RefCell, a mutable cell which provides mutability inside managed pointers. Currently it looks somewhat like this:
#[feature(managed_boxes)];
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
let state = #RefCell::new(A(123));
{
let mut r = state.borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
}
println!("{:?}", state)
}
You will get rather extensive output on the terminal though, because it will print internals of RefCell structure. See documentation on std::cell module for more information on cells and how to use them.
In the future Rust won't have special syntax for managed boxes at all. Garbage collection will be implemented in libraries. I believe the code will look like this (Rust authors, please correct me if I'm wrong):
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
// state is of type Gc<RefCell<State>>
let state = box(Gc) RefCell::new(A(123));
// Dereference will work for library pointer types, not sure about autodereference
let mut r = (*state).borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
println!("{:?}", *state)
}