Different behavior of KClass between Kotlin-jvm and Kotlin-js - reflection

I wrote some kotlin code to show a difference of behavior between the execution on jvm and in js. How could I fix this?
This equality: booleanKClass == genericKclass
is true for JVM
but false for JS
I’m going to paste the code followed by the output generated by the console (one for jvm and one for js)
If you call test1() from a multiplatform project you will see this as I did.
I’m using kotlin_version = ‘1.2.51’
fun test1() {
val values = PropertyDelegate()
val result = Result(values)
println("This will call the delegate getter.")
println("result.success is not really important but: ${result.success}")
println("This will call the delegate setter...")
result.success = true
println("end")
}
class Result(del: PropertyDelegate) {
var success: Boolean by del
}
class PropertyDelegate() {
inline operator fun <reified T> getValue(thisRef: Any?, property: KProperty<*>): T {
val booleanKClass = Boolean::class
val genericKclass = T::class
println("getValue (booleanKClass == genericKclass) is ${booleanKClass == genericKclass}")
return true as T
}
inline operator fun <reified T> setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val booleanKClass = Boolean::class
val genericKclass = T::class
println("setValue (booleanKClass == genericKclass) is ${booleanKClass == genericKclass}")
}
}
JVM output:
This will call the delegate getter.
getValue (booleanKClass == genericKclass) is true
result.success is true
This will call the delegate setter...
setValue (booleanKClass == genericKclass) is true
end
JS output:
This will call the delegate getter.
getValue (booleanKClass == genericKclass) is false
result.success is not really important but: true
This will call the delegate setter...
setValue (booleanKClass == genericKclass) is false
end

It works as expected since Kotlin 1.3.41.
Prints:
This will call the delegate getter.
getValue (booleanKClass == genericKclass) is true
result.success is not really important but: true
This will call the delegate setter...
setValue (booleanKClass == genericKclass) is true
end

Related

Recursively walk through nested structs

I want to build a method that takes a struct as an interface{} and returns true if any of the supplied struct's fields are nil.
Here's what I have at the moment:
// ContainsNil returns true if any fields within the supplied structure are nil.
//
// If the supplied object is not a struct, the method will panic.
// Nested structs are inspected recursively.
// Maps and slices are not inspected deeply. This may change.
func ContainsNil(obj interface{}) bool {
if obj == nil {
return true
}
s := reflect.Indirect(reflect.ValueOf(obj))
for i := 0; i < s.NumField(); i++ {
f := s.Type().Field(i)
field := s.Field(i)
if fieldIsExported(f) { // Exported-check must be evaluated first to avoid panic.
if field.Kind() == reflect.Struct {
if ContainsNil(field.Addr()) {
return true
}
} else {
if field.IsNil() {
return true
}
if field.Interface() == nil {
return true
}
}
}
}
return false
}
func fieldIsExported(field reflect.StructField) bool {
log.Println(field.Name)
return field.Name[0] >= 65 == true && field.Name[0] <= 90 == true
}
And a failing test:
func Test_ContainsNil_NilNestedValue_ReturnsTrue(t *testing.T) {
someNestedStruct := &c.SomeNestedStruct{
SomeStruct: c.SomeStruct{
SomeString: nil,
},
}
result := util.ContainsNil(someNestedStruct)
assert.True(t, result)
}
The test code executes without panicking, but fails because the method returns false rather than true.
The issue I'm having is that I can't figure out how to properly pass the nested struct back into the recursive call to ContainsNil.
When recursive call is made for the nested structure, the fieldIsExported method returns false because it's not receiving the value that I would expect it to be receiving.
I expect fieldIsExported to receive "SomeStruct" on its first call, and receive "SomeString" on the second (recursive) call. The first call goes as expected, but on the second call, fieldIsExported receives "typ", when I would expect it to receive "SomeString".
I've done a bunch of research about using reflect on structs, but I haven't been able to get my head around this yet. Ideas?
References:
Pass by reference nested structures through reflection
golang - reflection on embedded structs
https://golang.org/pkg/reflect/
Lot's of googling
You check if the current field is a struct value, but you never account for the case when it is a reflect.Ptr to a struct or something else, so your function never recurses for that case. Here is your function with the missing piece.
https://play.golang.org/p/FdLxeee9UU
// ContainsNil returns true if any fields within the supplied structure are nil.
//
// If the supplied object is not a struct, the method will panic.
// Nested structs are inspected recursively.
// Maps and slices are not inspected deeply. This may change.
func ContainsNil(obj interface{}) bool {
if obj == nil {
return true
}
s := reflect.Indirect(reflect.ValueOf(obj))
for i := 0; i < s.NumField(); i++ {
f := s.Type().Field(i)
field := s.Field(i)
if fieldIsExported(f) { // Exported-check must be evaluated first to avoid panic.
if field.Kind() == reflect.Ptr { // case when it's a pointer or struct pointer
if field.IsNil() {
return true
}
if ContainsNil(field.Interface()) {
return true
}
}
if field.Kind() == reflect.Struct {
if ContainsNil(field.Addr()) {
return true
}
} else {
if field.IsNil() {
return true
}
if field.Interface() == nil {
return true
}
}
}
}
return false
}

What's the behavior of Iterable#all & Why did Kotlin Char::class.java != char.javaClass

I'm trying an example in kotlin, like:
fun test(){
val harfler = listOf("a","b",'c','d')
println(harfler.all {
it.javaClass == String::class.java || it.javaClass == Char::class.java
})
}
List contains Char or String but all function in this expression returns false,Why return false?
Can anybody explain it?
Edit
for #JBNizet
As #JB Nizet has already told you how to analyze the problem.
According to the Mapped Types, The Kotlin Char will be mapped to Java Type decide on its declaration.
when declare as a non-nullable type Char it is a primitive Java type char.
when declare as a nullable type Char? it is a Java wrapper type Character.
when declare as a type argument List<Char> it is a Java wrapper type Character.
val it = 'a'
// v--- it should be `Any`
val array: Array<Any> = arrayOf('a')
// v--- char
println(it.javaClass)
// v--- print [java.lang.Character]
println(array.map { it.javaClass })
But I want to say that there is a different between the usage and the declaration.
For example, the parameter type it is a java.lang.Character, but its javaClass is char.
fun typeOf(it: Char?) = it?.javaClass
fun test() {
// v--- java.lang.Character
println(::typeOf.javaMethod!!.parameterTypes[0])
// v--- but it return `char` rather than `java.lang.Character`
println(typeOf('a'))
}
And the example below show the different as further, this is why I declare the array type to Array<Any> rather than Array<Char> in preceding example:
// v--- uses `java.lang.Character` instead
val array: Array<Char> = arrayOf('a')
// v--- java.lang.Character
println(array.javaClass.componentType)
// v--- [char]
println(array.map { it.javaClass })
Why did the strange behavior occurs in Koltin?
This is because Kotlin Char and other wrapper classes represent 2 roles. one is a Java primitive type char, another is a Java wrapper class java.lang.Character. However, Kotlin Char is statically which means you can't change its type in runtime. and a Char should be mapped to a char by default in Kotlin.
IF you want get the wrapper type every time, you should use KClass.javaObjectType instead, for example:
// v--- char
println(Char::class.java)
// v--- java.lang.Character
println(Char::class.javaObjectType)
The Iterable#all operation is a short-circuiting operation, which means if any first element didn't satisfied will return false immediately.
inline fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean {
// return `false` immediately the condition didn't satisfied
// v
for (element in this) if (!predicate(element)) return false
return true
}
When checking a Kotlin class like as Char and others. you should use the Kotlin type checking mechanism rather than traditional comparing approach, it helps you avoid such a confusion. for example:
val anything: Array<Any> = arrayOf('a')
val chars: Array<Char> = arrayOf('a')
println(chars.all { it is Char }) // print true
println(anything.all { it is Char }) // print true
So your code can replace with type checking as below:
fun test() {
val harfler = listOf("a", "b", 'c', 'd')
// v---------------v--- use type checking here
println(harfler.all { it is String || it is Char }) // print true
}

Swift 3: Sort (formerly sort-in-place) array by sort descriptors

Until now (Swift 2.2) I have been happily using the code from this answer - it's swifty, it's elegant, it worked like a dream.
extension MutableCollectionType where Index : RandomAccessIndexType, Generator.Element : AnyObject {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sortInPlace(sortDescriptors theSortDescs: [NSSortDescriptor]) {
sortInPlace {
for sortDesc in theSortDescs {
switch sortDesc.compareObject($0, toObject: $1) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: continue
}
}
return false
}
}
}
extension SequenceType where Generator.Element : AnyObject {
/// Return an `Array` containing the sorted elements of `source`
/// using criteria stored in a NSSortDescriptors array.
#warn_unused_result
public func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Generator.Element] {
return sort {
for sortDesc in theSortDescs {
switch sortDesc.compareObject($0, toObject: $1) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: continue
}
}
return false
}
}
}
Swift 3 changes everything.
Using the code migration tool and Proposal SE- 0006 - sort() => sorted(), sortInPlace() => sort() - I have gotten as far as
extension MutableCollection where Index : Strideable, Iterator.Element : AnyObject {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sort(sortDescriptors theSortDescs: [SortDescriptor]) {
sort {
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
extension Sequence where Iterator.Element : AnyObject {
/// Return an `Array` containing the sorted elements of `source`
/// using criteria stored in a NSSortDescriptors array.
public func sorted(sortDescriptors theSortDescs: [SortDescriptor]) -> [Self.Iterator.Element] {
return sorted {
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
The 'sorted' function compiles [and works] without problems. For 'sort' I get an error on the line that says 'sort' : "Cannot convert value of type '(_, _) -> _' to expected argument type '[SortDescriptor]'" which has me completely baffled: I do not understand where the compiler is trying to convert anything since I am passing in an array of SortDescriptors, which ought to BE an array of SortDescriptors.
Usually, this type of error means that you're handling optionals where you ought to have definite values, but since this is a function argument - and seems to work without a hitch in func sorted - all I can read from it is that 'something is wrong'. As of now, I have no idea WHAT that something is, and since we're in the early stages of beta, there is no documentation at all.
As a workaround, I have removed the sort (formerly sort-in-place) function from my code and replaced it with a dance of
let sortedArray = oldArray(sorted[...]
oldArray = sortedArray
but I'd be really grateful if I could get my sort-in-place functionality back.
Compare the methods available in Swift 2.2:
with the methods in Swift 3:
Notice that Swift 3 does not have a sort method that accepts an isOrderedBefore closure.
That is why your function won't compile.
This looks like a bug, so I reported it as bug 26857748 at bugreport.apple.com.
let sortedArray = users.sorted { $0.name < $1.name }
Use RandomAccessCollection protocol
extension MutableCollection where Self : RandomAccessCollection {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) {
sort { by:
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
In Swift 3.0
let sortedCapitalArray = yourArray.sorted {($0 as AnyObject).localizedCaseInsensitiveCompare(($1 as AnyObject)as! String) == ComparisonResult.orderedAscending}

Swift2 reflection help. Convert the value I get (type Any?) to Bool or Bool? accordingly

for a unit test of mine, I wrote a small helper that can get me a property Value by name.
let m = Mirror(reflecting: self)
let child1 = m.descendant(name)
now the problem is that the child has Type Any? but the properties real type is e.g. Bool? So Any is actually an Optional!
Thats why if child1 is Bool? never fires because Any? isn't the Bool?.
But child1! is Bool? doesn't compile.
And child1! is Bool isn't true!
So how do I 'unbox' this reflected Any? value?
a small example of what I mean
import UIKit
class ViewController: UIViewController {
let name = "asd"
let boolvalue: Bool = true
var optboolvalue: Bool? = true
override func viewDidLoad() {
print( getNumberForBool("boolvalue") )
print( getNumberForBool("optboolvalue") )
}
func getNumberForBool( name: String ) -> NSNumber {
let m = Mirror(reflecting: self)
let child1 = m.descendant(name)
if(child1 != nil) {
//! only works for bool, not for bool?
if let b = child1 as? Bool {
return NSNumber(bool: b)
}
//this would be my interpretation of how to do it ... unwrap the any and unwrap it again. this doesn't compile though :)
// if let b = child1! as! Bool? {
// return NSNumber(bool: b!)
// }
}
return NSNumber(bool: false)
}
}
NOTE
The type of child1 for the case Bool?:
▿ Optional(Optional(true))
▿ Some : Optional(true)
- Some : true
solution
I worked around the issue of not being able to cast an to Bool? by using reflection again
if let any = child1, let maybeB = Mirror(reflecting: any).descendant("Some") as? Bool {
if let b = (maybeB as Bool?) {
return NSNumber(bool: b)
}
}
reflection ^ 2 :D
the complete gist:
https://gist.github.com/Daij-Djan/18e8ab9bcbaa3f073523
the ?? operator unwraps the optional in case there is Some inside. If there is not, the value that is passed after eg. let foo = someOptional ?? alternativeValue.
This would give you an unwrapped Any. Since Swift is strongly typed you will only be getting the Bool if you would cast.
if let b = child, let c = b as? Bool {
return NSNumber(bool: c)
}

How can I use a Swift enum as a Dictionary key? (Conforming to Equatable)

I've defined an enum to represent a selection of a "station"; stations are defined by a unique positive integer, so I've created the following enum to allow negative values to represent special selections:
enum StationSelector : Printable {
case Nearest
case LastShown
case List
case Specific(Int)
func toInt() -> Int {
switch self {
case .Nearest:
return -1
case .LastShown:
return -2
case .List:
return -3
case .Specific(let stationNum):
return stationNum
}
}
static func fromInt(value:Int) -> StationSelector? {
if value > 0 {
return StationSelector.Specific(value)
}
switch value {
case -1:
return StationSelector.Nearest
case -2:
return StationSelector.LastShown
case -3:
return StationSelector.List
default:
return nil
}
}
var description: String {
get {
switch self {
case .Nearest:
return "Nearest Station"
case .LastShown:
return "Last Displayed Station"
case .List:
return "Station List"
case .Specific(let stationNumber):
return "Station #\(stationNumber)"
}
}
}
}
I'd like to use these values as keys in a dictionary. Declaring a Dictionary yields the expected error that StationSelector doesn't conform to Hashable. Conforming to Hashable is easy with a simple hash function:
var hashValue: Int {
get {
return self.toInt()
}
}
However, Hashable requires conformance to Equatable, and I can't seem to define the equals operator on my enum to satisfy the compiler.
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
The compiler complains that this is two declarations on a single line and wants to put a ; after func, which doesn't make sense, either.
Any thoughts?
Info on Enumerations as dictionary keys:
From the Swift book:
Enumeration member values without associated values (as described in
Enumerations) are also hashable by default.
However, your Enumeration does have a member value with an associated value, so Hashable conformance has to be added manually by you.
Solution
The problem with your implementation, is that operator declarations in Swift must be at a global scope.
Just move:
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
outside the enum definition and it will work.
Check the docs for more on that.
I struggled for a little trying to make an enum with associated values conform to Hashable.
Here's I made my enum with associated values conform to Hashable so it could be sorted or used as a Dictionary key, or do anything else that Hashable can do.
You have to make your associated values enum conform to Hashable because associated values enums cannot have a raw type.
public enum Components: Hashable {
case None
case Year(Int?)
case Month(Int?)
case Week(Int?)
case Day(Int?)
case Hour(Int?)
case Minute(Int?)
case Second(Int?)
///The hashValue of the `Component` so we can conform to `Hashable` and be sorted.
public var hashValue : Int {
return self.toInt()
}
/// Return an 'Int' value for each `Component` type so `Component` can conform to `Hashable`
private func toInt() -> Int {
switch self {
case .None:
return -1
case .Year:
return 0
case .Month:
return 1
case .Week:
return 2
case .Day:
return 3
case .Hour:
return 4
case .Minute:
return 5
case .Second:
return 6
}
}
}
Also need to override the equality operator:
/// Override equality operator so Components Enum conforms to Hashable
public func == (lhs: Components, rhs: Components) -> Bool {
return lhs.toInt() == rhs.toInt()
}
For more readability, let's reimplement StationSelector with Swift 3:
enum StationSelector {
case nearest, lastShown, list, specific(Int)
}
extension StationSelector: RawRepresentable {
typealias RawValue = Int
init?(rawValue: RawValue) {
switch rawValue {
case -1: self = .nearest
case -2: self = .lastShown
case -3: self = .list
case (let value) where value >= 0: self = .specific(value)
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .nearest: return -1
case .lastShown: return -2
case .list: return -3
case .specific(let value) where value >= 0: return value
default: fatalError("StationSelector is not valid")
}
}
}
The Apple developer API Reference states about Hashable protocol:
When you define an enumeration without associated values, it gains Hashable conformance automatically, and you can add Hashable conformance to your other custom types by adding a single hashValue property.
Therefore, because StationSelector implements associated values, you must make StationSelector conform to Hashable protocol manually.
The first step is to implement == operator and make StationSelector conform to Equatable protocol:
extension StationSelector: Equatable {
static func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
Usage:
let nearest = StationSelector.nearest
let lastShown = StationSelector.lastShown
let specific0 = StationSelector.specific(0)
// Requires == operator
print(nearest == lastShown) // prints false
print(nearest == specific0) // prints false
// Requires Equatable protocol conformance
let array = [nearest, lastShown, specific0]
print(array.contains(nearest)) // prints true
Once Equatable protocol is implemented, you can make StationSelector conform to Hashable protocol:
extension StationSelector: Hashable {
var hashValue: Int {
return self.rawValue.hashValue
}
}
Usage:
// Requires Hashable protocol conformance
let dictionnary = [StationSelector.nearest: 5, StationSelector.lastShown: 10]
The following code shows the required implementation for StationSelector to make it conform to Hashable protocol using Swift 3:
enum StationSelector: RawRepresentable, Hashable {
case nearest, lastShown, list, specific(Int)
typealias RawValue = Int
init?(rawValue: RawValue) {
switch rawValue {
case -1: self = .nearest
case -2: self = .lastShown
case -3: self = .list
case (let value) where value >= 0: self = .specific(value)
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .nearest: return -1
case .lastShown: return -2
case .list: return -3
case .specific(let value) where value >= 0: return value
default: fatalError("StationSelector is not valid")
}
}
static func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.rawValue == rhs.rawValue
}
var hashValue: Int {
return self.rawValue.hashValue
}
}
As of Swift 5.5 you can just write enum StationSelector: Hashable {}. Automatic conformance will be synthesized.
Just for emphasising what Cezar said before. If you can avoid having a member variable, you don't need to implement the equals operator to make enums hashable – just give them a type!
enum StationSelector : Int {
case Nearest = 1, LastShown, List, Specific
// automatically assigned to 1, 2, 3, 4
}
That's all you need. Now you can also initiate them with the rawValue or retrieve it later.
let a: StationSelector? = StationSelector(rawValue: 2) // LastShown
let b: StationSelector = .LastShown
if(a == b)
{
print("Selectors are equal with value \(a?.rawValue)")
}
For further information, check the documentation.

Resources