filter jython-generated property fields for getters/setters from dir() result - jython

I ran into a problem using java objects in jython today because jython is trying to be intelligent and automatically creates properties for (simple) getter/setter methods - For each method a field with the leading get/set removed and the next letter converted to lowercase is created:
//java code
class MyClass {
public List<Thing> getAllThings() { ... }
public List<Thing> getSpecificThings(String filter) { ... }
public void setSomeThing(SomeThing x) { ... }
[...]
}
#jython code
obj = MyClass()
hasattr(obj, "allThings") #-> True
hasattr(obj, "specificThings") #-> False because getSpecificThings has a param
hasattr(obj, "someThing") #-> False BUT
"someThing" in dir(obj) #-> True
The last line summarizes my problem here - the result of dir contains these fields (even when executed on obj.class instead of obj). I need a list of all methods callable on the object, which for my objects basically is the result of dir without these properties and filtered to exclude everything inherited from java.lang.Object and things starting with an underscore (the purpose of this is to automagically convert some python classes to java equivalents, e.g. dicts to Maps). In theory I could use __dict__ which doesn't contain them, but this would mean I'd have to recursively evaluate the base classes' __dict__s too, which I would like to avoid. What I am currently doing is seeing if the attribute actually exists and then check if it has an argslist attribute (meaning it is a method), which is true for every dir entry except for the generated properties:
for entry in dir(obj):
#skip things starting with an underscore or inherited from Object
if entry.startswith("_") or entry in dir(java.lang.Object): continue
#check if the dir entry is a fake setter property
if not hasattr(obj, entry): continue
#check if the dir entry has an argslist attribute (false for getter props)
e = getattr(obj, entry)
if not hasattr(e, "argslist"): continue
#start actual processing of the entry...
The problem with this approach is that the objects in question are interfaces to beans and a getSomething method typically fetches data from a database, so the getattr call for a property makes a roundtrip to the DB which can take multiple seconds and waste tons of memory.
Can I stop jython from generating these properties? If not, does anybody have an idea how I can filter out the properties without accessing them first? The only thing I could think of was checking if dir contains a method named get/set<property>, but this seems hackish and could generate false positives, which must be avoided.

The answer was easier than anticipated. While a hasattr of the property is True for an object instance, it is False for the objects class if the get-method in question is not static - the class doesn't have the property as you can't execute the method on it. The updated loop now looks like this:
for entry in dir(obj):
#skip things starting with an underscore or inherited from Object
if entry.startswith("_") or entry in dir(java.lang.Object): continue
#check if the dir entry is a fake property
if not hasattr(obj.class, entry): continue
#check if the dir entry has an argslist attribute (false if not a method)
e = getattr(obj, entry)
if not hasattr(e, "argslist"): continue
#start actual processing of the entry...

Related

Kotlin: Unusual behavior when dealing with sets

I have a simple data class which stores x and y coordinates of a position. My use case is that a single object of this class will be created and updated, and I need to maintain a set of unique coordinates.
I've simplified my use case in the following code where adding the pos object directly to the set vs passing the copy of the object result in different behavior (please see the comment in the code).
My initial hunch was that it could be because Java/Kotlin is passing the object by reference and the Set.add compares on reference. However, that doesn't seem to be true, if I set the pos.x or pos.y to any other value then the set.contains method returns false.
Question:
If the comparison is by reference then why does it fail when setting to a value other than what is given in the below code? If comparison is by hash code then why does the setByCopy not return true in the original case?
data class Pos(var x: Int = 0, var y: Int = 0)
fun main() {
val pos = Pos(0, 0)
val set = mutableSetOf<Pos>()
val setByCopy = mutableSetOf<Pos>()
pos.x = -9
pos.y = -6
set.add(pos)
setByCopy.add(pos.copy())
println(pos.hashCode())
pos.x = -8
pos.y = -37
// setting pos.y to any other value (e.g -35) will cause set.contains(pos) to return false.
println(set.contains(pos)) // true, but expected false.
println(setByCopy.contains(pos)) // false
}
As usual, modifying an element that's already in a set produces undefined behavior. This is not explicitly documented in Kotlin, but carries over from Java, where it's documented:
Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
This means that anything can happen: it can work or not work randomly.
You're creating two objects, pos and then a separate one we'll call pos2. When you invoke copy() on an instance of a data class, you get a completely separate instance with its properties initialised to the same data.
Then you add each instance to a separate Set. Even though set contains pos and setByCopy contains pos2, if you call setByCopy.contains(pos) then that will return true because of how equality works for sets and data classes:
boolean contains(Object o)
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
That o.equals(e) bit is important - a data class automatically generates an equals() implementation based on its data, i.e. the properties in the constructor. So Pos(0, 0) == Pos(0, 0) is true even though they're different instances, because they contain the same data.
This is why setByCopy.contains(pos) is true - not because it contains that object, but because it contains an object that is equal to it.
When you update pos with different numbers, now pos and pos2 have different values for their data properties - they're no longer equal, so setByCopy.contains(pos) returns false.
set.contains(pos) still evaulates to true because that set contains the pos object. When you updated that object, the reference in the set is pointing to that same object, so of course it's equal to itself! If you wanted to create a distinct, separate instance that doesn't change when you update pos, then that's what copy() is for

pass value by reference in kotlin

I want to pass a value to a function so when I change the value outside that function I could see it updated in my function as well. I know that when I pass Boxed types like Int, Boolean etc they passed by value. But looks like classes are passed by value as well:
data class TestClass(var b:Boolean)
fun printBooleanIn1sec(b: TestClass) {
Thread.sleep(1000L)
println(b.b)
}
fun main(args: Array<String>) {
var testClass = TestClass(false)
printBooleanIn1sec(testClass)
testClass.b = true
}
// prints "false"
Is there a way to pass something by reference but not by value in Kotlin if I need it?
Class instances are always passed by value of the reference. So the reference used in the function is pointing to the same thing as the reference passed to it, but you never have direct access to pointers in Kotlin/Java. It's important to make this distinction because "pass by reference" would mean that the function could end up looking at a different object if the higher code on the stack changed what its variable was pointing at.
The reason your code prints false is that the Thread you're sleeping is the same one that called your function, and printBooleanIn1sec() returns before testClass.b = true is reached. To illustrate the situation you wanted, you would need to spin up a new thread that sleeps and then prints the value, like:
fun printBooleanIn1sec(b: TestClass) {
thread {
Thread.sleep(1000L)
println(b.b)
}
}
Primitives are abstracted away in Kotlin, so you don't have to think of them differently than a class. But like any other immutable class, you can't change their value at all when you pass them into a function. If you want to "see" changes in the function that occur elsewhere, you'll have to wrap them in classes that hold a var property for them.

Boolean getter is serialized twice when annotated with #JsonProperty

Suppose there is a class with a boolean property, its name starts with is:
class Preferrable {
var isPreferred: Boolean = true
}
It is serialized to {"preferred":true}, dropping is part.
As mentioned in this question, to prevent it, we need to specify property name explicitly, using #JsonProperty("isPreferred") annotation.
That approach works perfectly with Java. But in case of Kotlin class with annotated property serialized form contains property duplication: {"preferred":true,"isPreferred":true}.
The workaround is to apply annotation to property getter. It doesn't work for data classes and as for me, this code looks a bit too much for just keeping property name as is:
class Preferrable {
var isPreferred: Boolean = true
#JsonProperty(value = "isPreferred")
get() = field
}
What is the reason behind such behavior? Is it just a bug? Is there a simpler way to prevent is prefix dropping for Kotlin?
Booleans are handled a bit differently from other data types. You need to explicitly use #get in the annotation:
#get:JsonProperty("isPreferred")
var isPreferred: Boolean = true
Note that this does work with data classes, e.g.
data class Preferrable(
#get:JsonProperty("isPreferred")
var isPreferred: Boolean = true
)
See this question for a bit more info (and a link to where this is discussed in more detail).

Using public and private methods inside their class in Perl 6

If I have a public method, I can call it inside its class using both $.name and self.name:
class TEST {
has Int $.a;
method b($x) {
return $!a * $x;
}
method c($y) {
return self.b($y) * 3; # or $.b($y)
}
}
my $m = TEST.new(a => 10);
say $m.c(2); # 60
But if I make b a private method, I only can call it with self!b, not $!b, otherwise I get the following error message:
Attribute $!b not declared in class TEST
What's behind this rule? What are the rules of calling a method inside its own class?
An attribute can always be referred to as $!foo in a class. If you do that, than the code will be generated to directly access the attribute itself, and any classes subclassing your class will not be able to change this behaviour.
If you use has $.foo in the declaration of a class, it means that a public accessor (and if you add is rw it can also function as a mutator).
When you use $.foo in your code otherwise, it is exactly the same as $( self.foo ). This means that it will call the method foo on self, and itemize the return value (make it a single "thing" if it wasn't yet). This will go wrong if you defined your attribute with $!foo and you did not supply a method foo yourself.
This goes even further: $.bar really means self.bar: you only need to have a method existing by the name bar, which may not be related to any attribute at all.
If you define a private method !baz, the ! just indicates the privacy of the method, which means you need to call it indeed as self!baz. There is no short syntax for it.
Personally I dislike the fact that you can say $.zippo even if zippo is not an attribute. But I'm afraid that ship has sailed. But this behaviour is now causing you confusion :-(
So what's behind the rule for not having a short syntax for calling a private method? Not sure, I guess really that $!foo was already taken to mean direct access to the attribute, and provide you with a compile time error if the attribute doesn't exist.
Hope this answers your question!

How to clear a persistent variable in a MATLAB method

I have a MATLAB class that contains a method that employs a persistent variable. When certain conditions are met I need to clear the persistent variable without clearing the object to which the method belongs. I've been able to do this, but only by employing clear functions which has excessively broad scope for my purposes.
The classdef .m file for this problem:
classdef testMe
properties
keepMe
end
methods
function obj = hasPersistent(obj)
persistent foo
if isempty(foo)
foo = 1;
disp(['set foo: ' num2str(foo)]);
return
end
foo = foo + 1;
disp(['increment foo: ' num2str(foo)]);
end
function obj = resetFoo(obj)
%%%%%%%%%%%%%%%%%%%%%%%%%
% this is unacceptably broad
clear functions
%%%%%%%%%%%%%%%%%%%%%%%%%
obj = obj.hasPersistent;
end
end
end
A script that employs this class:
test = testMe();
test.keepMe = 'Don''t clear me bro';
test = test.hasPersistent;
test = test.hasPersistent;
test = test.hasPersistent;
%% Need to clear the persistent variable foo without clearing test.keepMe
test = test.resetFoo;
%%
test = test.hasPersistent;
test
The output from this is:
>> testFooClear
set foo: 1
increment foo: 2
increment foo: 3
increment foo: 4
set foo: 1
test =
testMe
Properties:
keepMe: 'Don't clear me bro'
Methods
which is the desired output. The problem is that the line clear functions in the classdef file clears all functions in memory. I need a way to clear with a much smaller scope. For example, if hasPersistent' was a function instead of a method, the appropriately scoped clear statement would beclear hasPersistent`.
I know that clear obj.hasPersistent and clear testMe.hasPersistent both fail to clear the persistent variable. clear obj is similarly a bad idea.
Following the discussion in the comments, I think you want to use make foo a private property, accompanied with appropriate increment/reset public functions.
You definitely don't need a persistent variable to implement what you want. But, in any case, to remove a persistent variable from a class method you have to clear the corresponding class. In your case, clear testMe should do what you want.
A related issue is how to clear a persistent variable in a package function. To remove persistent variable myVar from function foo within package foo_pkg you have to do this:
clear +foo_pkg/foo
This should work as long as the parent folder of folder +foo_pkg is in the MATLAB path.