Given Kotlin 1.1. For an instance of some class, instance::class.java and instance.javaClass seem to be nearly equivalent:
val i = 0
println(i::class.java) // int
println(i.javaClass) // int
println(i::class.java === i.javaClass) // true
There is a subtle difference, however:
val c1: Class<out Int> = i::class.java
val c2: Class<Int> = i.javaClass
instance.javaClass is negligibly shorter, but instance::class.java is more consistent with the corresponding usage on a type. While you can use .javaClass on some types, the result may not be what you would expect:
println(i::class.java === Int::class.java) // true
println(i.javaClass === Int.javaClass) // false
println(Int::class.java === Int.javaClass) // false
println(Int.javaClass) // class kotlin.jvm.internal.IntCompanionObject
So, I would argue that it is better to never use .javaClass for more consistency. Are there any arguments against that?
The difference in these two constructs is that, for an expression foo of static (declared or inferred) type Foo:
foo.javaClass is typed as Class<Foo>
foo::class.java is typed as Class<out Foo>
In fact, the latter is more precise, because the actual value that foo evaluates to can be an instance of not Foo itself but one of its subtypes (and it's exactly what's denoted by the covariant out Foo).
As #marstran correctly noted in the comment on the question, .javaClass once was considered to be deprecated (see the Kotlin 1.1 RC announcement) because it can break type safety (see below), but it was afterwards left as-is because it was widely used and replacing it with the alternative of ::class.java would require adding explicit unchecked casts in the code.
Also, see the comments under this answer: (link)
Please note that Int.javaClass does not denote the type of Int but instead is the Java class of the Int's companion object. Whereas Int::class.java is an unbound class reference and denotes the type. To get it with .javaClass, you need to call it on an Int instance, e.g. 1.javaClass.
Here's how exactly .javaClass can break type safety. This code compiles but breaks at runtime:
open class Foo
class Bar : Foo() {
val baz: Int = 0
}
fun main(args: Array<String>) {
val someFoo: Foo = Bar()
val anotherFoo: Foo = Foo()
val someFooProperty: KProperty1<in Foo, *> = // 'in Foo' is bad
someFoo.javaClass.kotlin.memberProperties.first()
val someValue = someFooProperty.get(anotherFoo)
}
This example uses kotlin-reflect.
That's because someFooProperty represents a property of Bar, not Foo, but since it was obtained from someFoo.javaClass (Class<Foo> then converted to KClass<Foo>) the compiler allows us to use it with the in Foo projection.
Related
I would like to have a way to describe logic/spec level structs that include abstract lists. Example 2.2.7 on page 27 of the ACSL Reference Manual suggests that there is a
way to do this and it is as follows:
//# type point = struct { real x; real y; };
//# type triangle = point[3];
//# logic point origin = { .x = 0.0 , .y = 0.0 };
/*# logic triangle t_iso = { [0] = origin,
# [1] = { .y = 2.0 , .x = 0.0 }
# [2] = { .x = 2.0 , .y = 0.0 }};
#*/
/*# logic point centroid(triangle t) = {
# .x = mean3(t[0].x,t[1].x,t[2].x);
# .y = mean3(t[0].y,t[1].y,t[2].y);
# };
#*/
//# type polygon = point[];
/*# logic perimeter(polygon p) =
# \sum(0,\length(p)-1,\lambda integer i;d(p[i],p[(i+1) % \length(p)])) ;
#*/
If I copy/paste this exact code into a text editor and try to run this code with the wp plugin with:
frama-c -wp -wp-rte -wp-prover alt-ergo shapes.c
I get an error:
[kernel:annot-error] shapes.c:1: Warning: unexpected token '{'
If I give up on trying to write logic/spec level declarations of struct types, but would still like to write logic/spec level expressions that instantiate structs defined in C as follows:
struct somestruct {
int x;
int y;
};
/*#
logic struct somestruct foo = { .x = 3, .y = 4 };
*/
I still get an error:
[kernel:annot-error] aggregate_err.c:7: Warning:
unsupported aggregated field construct. Ignoring global annotation
and not having a way to write particular values of structs as expressions in specifications leads to some fairly ugly specifications, so I am hoping that I am doing something wrong.
If I dig into the source of frama-C 20.0 to try to find the part of the parser-generator code for /*# type declarations, it looks like the syntax in Ex 2.2.7 is not really implemented. It looks like the syntax for type level declarations is line 799 of
frama-c-20.0-Calcium/src/kernel_internals/parsing/logic_parser.mly
(called type_spec)
And the parse rule for type level declarations of structs is:
| STRUCT exit_rt_type identifier_or_typename { LTstruct $3 }
which looks like it would support
//# type foo = struct c_struct;
but not something like what Ex 2.2.7 has as in:
//# type point = struct { real x; real y; };
Is there something else I should be doing to have better support for structs in ACSL/Frama-C? Thanks!
Not all ACSL constructions are supported by the current Frama-C implementation. With each Frama-C release comes an ACSL implementation manual, which describes the constructions that are not yet implemented. For Frama-C 20.0 Calcium, this can be found here. In this document, unsupported constructions appear in red in the relevant BNF rule. Note however that other parts of the manual are left untouched. Notably, the fact that an example is included in the implementation manual does not imply that it is expected to be successfully parsed by the current Frama-C version. In your case, these are the rules of figure 2.17 on page 57, which show that indeed records are not implemented.
As you have already discovered by yourselves, it is indeed possible to define a C struct (possibly ghost) and an ACSL type out of it. Of course, since the struct lives in the C world, its fields must have C types (ACSL types in ghost declarations is unsupported as well).
Similarly, you can simulate the absence of direct record definition by an update (the \with construction) of all the fields of an arbitrary record, as in the following example:
//# ghost struct c_s { float x; float y; };
//# type point = struct c_s;
//# axiomatic Arbitrary_point { logic point empty; }
//# logic point my_point = {{ empty \with .x = (float)1. } \with .y = (float)2.};
I often find myself needing to do the following, and Flow makes it stupidly difficult:
/* #flow */
type Foo = {
+foo?: number,
}
type FooBar = {
+foo?: number,
+bar?: number,
}
const foo: Foo = {foo: 2}
function process(arg: $ReadOnly<FooBar>) {
}
process(foo)
Is there any good way to do this? I get the following error:
17: process(foo)
^ Cannot call `process` with `foo` bound to `arg` because property `bar` is missing in `Foo` [1] but exists in `FooBar` [2].
References:
12: const foo: Foo = {foo: 2}
^ [1]
14: function process(arg: $ReadOnly<FooBar>) {
^ [2]
Flow defaults to object types being inexact; this means that, although Foo is only declared to explicitly have a single (optional) property foo of type number, a variable of type Foo could theoretically have additional properties. For example, a variable of type Foo could have a property bar. And, since bar is not typed in Foo, bar's type is unrestricted (i.e., not necessarily number). As a result, if you were to interact with arg.bar in process and Flow allowed arg to be of type Foo, you are not guaranteed to be interacting with a number. Thus, Flow complains.
One way to fix this is to use exact object types. If Flow knows that a variable of type Foo will never have a bar property, then it can safely be passed into process. So, you could type Foo as:
type Foo = {|
+foo?: number,
|};
Try Flow
(Note: the $ReadOnly utility type is not necessary with the above definition of Foo and the original definition of FooBar because bar is not writable. Though, certainly, it's fine to keep $ReadOnly.)
In GO, I learnt that,
1)
Programmer can only define methods on named types(X) or pointer(*X) to named types
2)
An explicit method definition for type X implicitly defines the same method for type *X and vice versa, so, my understanding is, If I declare,
func (c Cat) foo(){
//do stuff_
}
and declare,
func (c *Cat) foo(){
// do stuff_
}
then GO compiler gives,
Compile error: method re-declared
which indicates that, pointer method is implicitly defined and vice versa
With the given named type(Cat),
type Cat struct{
Name string
Age int
Children []Cat
Mother *Cat
}
Scenario 1
Method(foo) defined on a named type(Cat), by programmer,
func (c Cat) foo(){
// do stuff....
}
that implicitly defines method(foo) on pointer(*Cat) to named type, by GO compiler, that looks like,
func (c *Cat) foo(){
// do stuff....
}
On creating variables of named type(Cat)
var c Cat
var p *Cat = &c
c.foo() has the method defined by programmer.
Question 1:
On invoking p.foo(), does implicit pointer method receive the pointer(p)?
Scenario 2
Method(foo) defined on a pointer(*Cat) to named type, by the programmer,
func (c *Cat) foo(){
// do stuff....
}
that implicitly defines method(foo) on named type(Cat), by the GO compiler, that looks like,
func (c Cat) foo(){
// do stuff....
}
On creating variables of named type(Cat)
var c Cat
var p *Cat = &c
p.foo() has method defined by programmer(above).
Question 2:
On invoking c.foo(), does the implicit non-pointer method receive the value c?
An explicit method definition for type X implicitly defines the same method for type *X and vice versa.
This is not correct. Methods are not defined implicitly. The only thing that a compiler does for you is implicitly replacing c.foo() with (*c).foo() or c.foo() with (&c).foo() for convenience. See the tour of Go
The receiver of the method is either of type T or of type *T, based on your explicit declaration.
Beginner in Kotlin here.
I try to create and populate objects by reflection in a program. I cannot find the equivalent functionality in pure kotlin so my solution resembles the code below which works fine, but requires the use of dirty references like java.lang.String::class.java and intelliJ, understandably, doesn't seem to like this. Is there a simpler way that I am missing to do this?
val jclass = myObject::class.java
val setters = jclass.declaredMethods.filter { it.name.startsWith("set") }
for (s in setters) {
val paramType = s.parameterTypes.first()
val data = when(paramType) {
java.lang.Integer::class.java -> foo
java.lang.Double::class.java -> bar
java.lang.String::class.java -> baz
}
s.invoke(myObject, data)
}
You can use Kotlin reflection, which requires you to add kotlin-reflect as a dependency to your project.
Here you can find kotlin-reflect for Kotlin 1.0.5, or pick another version if you use different Kotlin version.
After that, you can rewrite your code as follows:
val properties = myObject.javaClass.kotlin.memberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
val data = when (p.returnType.javaType) {
Int::class.javaPrimitiveType,
Int::class.javaObjectType -> foo
Double::class.javaPrimitiveType,
Double::class.javaObjectType -> bar
String::class.java -> baz
else -> null
}
if (data != null)
p.setter.call(myObject, data)
}
Some details:
Despite using Kotlin reflection, this approach works with Java classes as well, their fields and accessors will be seen as properties, as described here.
Just like with Java reflection, memberProperties returns public properties of this type and all its supertypes. To get all the properties declared in the type (including the private ones, but not those from the supertypes), use declaredMemberProperties instead.
.filterIsInstance<KMutableProperty<*> returns only the mutable properties, so that you can use their p.setter later. If you need to iterate over the getters of all the properties, remove it.
In the when block, I compared p.returnType.javaType to Int::class.javaPrimitiveType and Int::class.javaObjectType, because what's Int in Kotlin can be mapped to either Java int or java.lang.Integer depending on its usage. In Kotlin 1.1, it will be enough to check p.returnType.classifier == Int::class.
If You need to get property getter/setter, there is a couple of built-in constructions for it YourClass::propertyName
have a look at example bellow
fun main(args: Array<String>) {
val myObject = Cat("Tom", 3, 35)
println(Cat::age.getter.call(myObject)) // will print 3
Cat::age.setter.call(myObject, 45)
print(myObject) // will print Cat(name=Tom, age=45, height=35)
}
data class Cat(var name : String, var age : Int, val height : Int)
but sometimes you don't know class exactly(working with generics) or need to get list of properties, then use val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>> it will return all properties, some of them can be mutable(var) and some immutable(val), you can find out immutability by checking belonging to KMutableProperty<*> (by filtering with is operator or using convenience methods such as filterIsInstance<KMutableProperty<*>>)
about your code snippet
I absolutely agree with hotkey, but now it is better to use myObject::class.declaredMemberProperties instead of myObject.javaClass.kotlin.memberProperties
because the second one is deprecated
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html
data class Cat(var name : String, var age : Int, val height : Int)
#JvmStatic
fun main(args: Array<String>) {
val myObject = Cat("Tom", 3, 35)
val properties = myObject::class.declaredMemberProperties
for (p in properties.filterIsInstance<KMutableProperty<*>>()) {
val data = when (p.returnType.javaType) {
Int::class.javaPrimitiveType,
Int::class.javaObjectType -> 5
String::class.java -> "Rob"
else -> null
}
if (data != null)
p.setter.call(myObject, data)
}
println(myObject)
// it will print Cat(name=Rob, age=5, height=35),
// because height isn't var(immutable)
}
in general, I would approach similar problems with such construction in mind
val myObject = Cat("Tom", 3, 35)
Cat::class.declaredMemberProperties
//if we want only public ones
.filter{ it.visibility == KVisibility.PUBLIC }
// We only want strings
.filter{ it.returnType.isSubtypeOf(String::class.starProjectedType) }
.filterIsInstance<KMutableProperty<*>>()
.forEach { prop ->
prop.setter.call(myObject, "Rob")
}
println(myObject)
//it will print Cat(name=Rob, age=3, height=35),
//because name is only eligible in this case
I'm having trouble wrapping my head around how pointers, slices, and interfaces interact in Go. This is what I currently have coded up:
type Loader interface {
Load(string, string)
}
type Foo struct {
a, b string
}
type FooList []Foo
func (l FooList) Load(a, b string) {
l = append(l, Foo{a, b})
// l contains 1 Foo here
}
func Load(list Loader) {
list.Load("1", "2")
// list is still nil here
}
Given this setup, I then try to do the following:
var list FooList
Load(list)
fmt.Println(list)
However, list is always nil here. My FooList.Load function does add an element to the l slice, but that's as far as it gets. The list in Load continues to be nil. I think I should be able to just pass the reference to my slice around and have things append to it. I'm obviously missing something on how to get it to work though.
(Code in http://play.golang.org/p/uuRKjtxs9D)
If you intend your method to make changes, you probably want to use a pointer receiver.
// We also define a method Load on a FooList pointer receiver.
func (l *FooList) Load(a, b string) {
*l = append(*l, Foo{a, b})
}
This has a consequence, though, that a FooList value won't itself satisfy the Loader interface.
var list FooList
Load(list) // You should see a compiler error at this point.
A pointer to a FooList value, though, will satisfy the Loader interface.
var list FooList
Load(&list)
Complete code below:
package main
import "fmt"
/////////////////////////////
type Loader interface {
Load(string, string)
}
func Load(list Loader) {
list.Load("1", "2")
}
/////////////////////////////
type Foo struct {
a, b string
}
// We define a FooList to be a slice of Foo.
type FooList []Foo
// We also define a method Load on a FooList pointer receiver.
func (l *FooList) Load(a, b string) {
*l = append(*l, Foo{a, b})
}
// Given that we've defined the method with a pointer receiver, then a plain
// old FooList won't satisfy the Loader interface... but a FooList pointer will.
func main() {
var list FooList
Load(&list)
fmt.Println(list)
}
I'm going to simplify the problem so it's easier to understand. What is being done there is very similar to this, which also does not work (you can run it here):
type myInt int
func (a myInt) increment() { a = a + 1 }
func increment(b myInt) { b.increment() }
func main() {
var c myInt = 42
increment(c)
fmt.Println(c) // => 42
}
The reason why this does not work is because Go passes parameters by value, as the documentation describes:
In a function call, the function value and arguments are evaluated in the usual
order. After they are evaluated, the parameters of the call are passed by value
to the function and the called function begins execution.
In practice, this means that each of a, b, and c in the example above are pointing to different int variables, with a and b being copies of the initial c value.
To fix it, we must use pointers so that we can refer to the same area of memory (runnable here):
type myInt int
func (a *myInt) increment() { *a = *a + 1 }
func increment(b *myInt) { b.increment() }
func main() {
var c myInt = 42
increment(&c)
fmt.Println(c) // => 43
}
Now a and b are both pointers that contain the address of variable c, allowing their respective logic to change the original value. Note that the documented behavior still holds here: a and b are still copies of the original value, but the original value provided as a parameter to the increment function is the address of c.
The case for slices is no different than this. They are references, but the reference itself is provided as a parameter by value, so if you change the reference, the call site will not observe the change since they are different variables.
There's also a different way to make it work, though: implementing an API that resembles that of the standard append function. Again using the simpler example, we might implement increment without mutating the original value, and without using a pointer, by returning the changed value instead:
func increment(i int) int { return i+1 }
You can see that technique used in a number of places in the standard library, such as the strconv.AppendInt function.
It's worth keeping a mental model of how Go's data structures are implemented. That usually makes it easier to reason about behaviour like this.
http://research.swtch.com/godata is a good introduction to the high-level view.
Go is pass-by-value. This is true for both parameters and receivers. If you need to assign to the slice value, you need to use a pointer.
Then I read somewhere that you shouldn't pass pointers to slices since
they are already references
This is not entirely true, and is missing part of the story.
When we say something is a "reference type", including a map type, a channel type, etc., we mean that it is actually a pointer to an internal data structure. For example, you can think of a map type as basically defined as:
// pseudocode
type map *SomeInternalMapStructure
So to modify the "contents" of the associative array, you don't need to assign to a map variable; you can pass a map variable by value and that function can change the contents of the associative array pointed to by the map variable, and it will be visible to the caller. This makes sense when you realize it's a pointer to some internal data structure. You would only assign to a map variable if you want to change which internal associative array you want it to point to.
However, a slice is more complicated. It is a pointer (to an internal array), plus the length and capacity, two integers. So basically, you can think of it as:
// pseudocode
type slice struct {
underlyingArray uintptr
length int
capacity int
}
So it's not "just" a pointer. It is a pointer with respect to the underlying array. But the length and capacity are "value" parts of the slice type.
So if you just need to change an element of the slice, then yes, it acts like a reference type, in that you can pass the slice by value and have the function change an element and it's visible to the caller.
However, when you append() (which is what you're doing in the question), it's different. First, appending affects the length of the slice, and length is one of the direct parts of the slice, not behind a pointer. Second, appending may produce a different underlying array (if the capacity of the original underlying array is not enough, it allocates a new one); thus the array pointer part of the slice might also be changed. Thus it is necessary to change the slice value. (This is why append() returns something.) In this sense, it cannot be regarded as a reference type, because we are not just "changing what it points to"; we are changing the slice directly.