Understanding UnsafeRawPointer in objc_setAssociatedObject - objective-c

I'd like to set n number of associated objects to an object in Swift
My understanding is the usual pattern for the UnsafeRawPointer reference is like this...
static var reference = "someRef"
public func add(to myObject: AnyObject) {
let adding = ThingToAdd()
objc_setAssociatedObject(myObject, &reference, adding, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
but this wouldn't work for n number of calls to add(to:)
Similarly, the below code works fine if I only call it once per myObject.. However, if I add another associated object in the same way... it replaces the first ThingToAdd with the second. Building a unique string inline does not work. On the simulator it's fine but on a device it's not.
public func add(to myObject: AnyObject) {
let adding = ThingToAdd()
var reference = "objectref\(UUID().uuidString)".replacingOccurrences(of: "-", with: "")
objc_setAssociatedObject(myObject, reference, adding, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
I understand that this is incorrect, however I don't know how to create n number of UnsafeRawPointers in order to store the associated objects with unique references.
Any help / explanation would be greatly appreciated.

Passing reference to the key: UnsafeRawPointer argument of objc_setAssociatedObject passes the address of the variable storage to that function.
Global variables and static member variables (and only those) are guaranteed to have a fixed address.
In your first version, the second and all subsequent calls to objc_setAssociatedObject with the same key replace a previous association.
In your second version, the address of a local variable is passed as key. That address may or may not be the same on subsequent calls. Note that the contents of the string is irrelevant, the key is just a pointer, i.e. the address of that variable.
If you need to associate a variable number of values with a given object then I would suggest to associate a single NSMutableArray (or NSMutableDictionary) and add the values to that array or dictionary.

Related

Kotlin modifying dataclass object key from map changes the reference after modifying variable

I have a MutableMap that its keys are objects from a DataClass (User dataclass), and the values are arrays from other Dataclass (Dog dataclass). If i have a variable with a User object, and i put it in the MutableMap and i test if the map contains the User, it says that is true. But after putting the user in the MutableMap if i change one of the attributes of the User object using the variable that holds the User object, the Map says that it doesnt contains the user object.
This is an example
data class User(
var name: String,
var project: String,
)
data class Dog(
var kind: String
)
fun main(args: Array<String>) {
var mapUserDogs: MutableMap<User, MutableList<Dog>> = mutableMapOf()
var userSelected = User("name2", "P2")
mapUserDogs.put(
User("name1", "P1"),
mutableListOf(Dog("R1"), Dog("R2"))
)
mapUserDogs.put(
userSelected,
mutableListOf(Dog("R21"), Dog("R31"))
)
println(userSelected)
println(mapUserDogs.keys.toString())
println(mapUserDogs.contains(userSelected))
println(mapUserDogs.values.toString())
println("\n")
userSelected.name = "Name3"
println(userSelected)
println(mapUserDogs.keys.toString())
println(mapUserDogs.contains(userSelected))
println(mapUserDogs.values.toString())
}
The prints statements show this:
User(name=name2, project=P2)
[User(name=name1, project=P1), User(name=name2, project=P2)]
true
[[Dog(kind=R1), Dog(kind=R2)], [Dog(kind=R21), Dog(kind=R31)]]
User(name=Name3, project=P2)
[User(name=name1, project=P1), User(name=Name3, project=P2)]
false
[[Dog(kind=R1), Dog(kind=R2)], [Dog(kind=R21), Dog(kind=R31)]]
Process finished with exit code 0
But it doesn't make sense. Why the map says that it doesn't contains the user object if its clear that it still holds the reference to it after being modified?
User(name=Name3, project=P2)
[User(name=name1, project=P1), User(name=Name3, project=P2)]
The user in the keys collection was also changed when i modified the userSelected variable, so now the object has it attribute name as "Name3" in both the variable and in the Map keys, but it still says that it doesnt contains it.
What can i do so that i can change the attributes in the userSelected object and the Map still return true when using the "contains" method?. And doing the same process in reverse shows the same. If i get from the map the user and i modify it, the userVariable is also modified but if i later test if the map contains the userVariable, it says false.
What can i do so that i can change the attributes in the userSelected object and the Map still return true when using the "contains" method?
There is nothing you can do that preserves both your ability to look up the entry in the map and your ability to modify the key.
Make your data class immutable (val instead of var, etc.), and when you need to change a mapping, remove the old key and put in the new key. That's really the only useful thing you can do.
To add to Louis Wasserman's correct answer:
This is simply the way that maps work in Kotlin: their contract requires that keys don't change significantly once stored. The docs for java.util.Map* spell this out:
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
The safest approach is to use only immutable objects as keys. (Note that not just the object itself, but any objects it references, and so on, must all be immutable for it to be completely safe.)
You can get away with mutable keys as long as, once the key is stored in the map, you're careful never to change anything that would affect the results of calling equals() on it. (This may be appropriate if the object needs some initial set-up that can't all be done in its constructor, or to avoid having both mutable and immutable variants of a class.) But it's not easy to guarantee, and leaves potential problems for future maintenance, so full immutability is preferable.
The effects of mutating keys can be obvious or subtle. As OP noticed, mappings may appear to vanish, and maybe later reappear. But depending on the exact map implementation, it may cause further problems such as errors when fetching/adding/removing unrelated mappings, memory leaks, or even infinite loops. (“The behaviour… is not specified” means that anything can happen!)
What can i do so that i can change the attributes in the userSelected object and the Map still return true when using the "contains" method?
What you're trying to do there is to change the mapping. If you store a map from key K1 to value V, and you mutate the key to hold K2, then you're effectively saying “K1 no longer maps to V; instead, K2 now maps to V.”
So the correct way to do that is to remove the old mapping, and then add the new one. If the key is immutable, that's what you have to do — but even if the key is mutable, you must remove the old mapping before changing it, and then add a new mapping after changing it, so that it never changes while it's stored in the map.
(* The Kotlin library docs don't address this, unfortunately — IMHO this is one of many areas in which they're lacking, as compared to the exemplary Java docs…)
That happens because data classes in Kotlin are compared by value, unlike regular classes which are compared by reference. When you use a data class as a key, the map gets searched for a User with the same string values for the name and project fields, not for the object itself in memory.
For example:
data class User(
var name: String,
var project: String,
)
val user1 = User("Daniel", "Something Cool")
val user2 = User("Daniel", "Something Cool")
println(user1 == user2) // true
works because, even though they are different objects (and thus different references), they have the same name and project values.
However, if I were to do this:
user1.name = "Christian"
println(user1 == user2) // false
the answer would be false because they don't share the same value for all of their fields.
If I made User a standard class:
class User(
var name: String,
var project: String,
)
val user1 = User("Daniel", "Something Cool")
val user2 = User("Daniel", "Something Cool")
println(user1 == user2) // false
the answer would be false because they are different references, even though they share the same values.
For your code to work the way you want, make User a regular class instead of a data class.
That's the key difference between regular classes and data classes: a class is passed by reference, a data class is passed by value. Data classes are nothing more than collections of values with (optionally) some methods attached to them, classes are individual objects.

Declaring a variable belonging to a user-defined class in Perl 6

When I declare a variable, whose value belongs to a built-in class, I simply write
my Int $a;
But when I want to use a user-defined class, I have to use Classname.new.
my class House {
has $.area is rw;
}
my $house1 = House.new;
$house1.area = 200;
say $house1.area;
So, my naïve question is, what's the reason of that difference? Why can't we simply write my House $house1?
My ultimate goal is to use an array whose values are instances of a user-defined class. How can I do the following correctly?
my #houses ...;
#houses[10].area = 222;
my House $a does the same as my Int $a. It puts a restriction on the values that you can put in it. If you look at the content of the variable, you will get the type object of that restriction.
There is a trick that you can use though, so you don't have to repeat the House bit: my House $a .= new, which is the equivalent of my House $a = House.new.
To get back to your question: yes, you can do that with some trouble:
class House {
has $.area;
multi method area(House:U \SELF:) is raw {
(SELF = House.new).area
}
multi method area(House:D:) is raw {
$!area
}
}
my House #houses;
#houses[2].area = 42;
say #houses # [(House) (House) House.new(area => 42)]
We create two candidates for the accessor method: one taking an undefined type object, and the other an instantiated object. The first one modifies its invocant (assuming it to be a container that can be set), then calls the instantiated version of the method. I'm leaving this as an exercise to the reader to turn this into an Attribute trait.
When you write my Int $a; you will have a variable of type Int, but without value, or even container. The concrete value of $a will be (Int).
The same with my House $house; - you will get (House) value.
In your case you have to initialize array's elements by some House value. For example:
my #houses = House.new() xx 11;
#houses[10].area = 222;
I think you're missing the part that the compiler is doing some of the work for you. When you have a literal number, the parser recognizes it and constructs the right numeric object for it. There's a virtual and unseen Int.new() that has already happened for you in rakudo/src/Perl6/Actions.nqp. It's at the NQP level but it's the same idea.

pin_ptr of List rather than array

I use pin_ptr for cli::array types and everything works fine.
Is it possible to do the same with System::Collection::Generic::List which I believe is a contiguous block of memory?
The obvious
List<double>^ stuff = gcnew List<double>( 10 );
cli::pin_ptr<double> resultPtr = &stuff[ 0 ];
gives a compiler error "error C2102: '&' requires l-value" presumably because the indexed property returns something that is not a l-value! So is there another way to do this. I have played around with interior_ptr as well but have not found anything that works yet.
I know that I could call ToArray on the List but the whole point is to not copy stuff around.
No, this is not possible.
True, a List does use an array behind the scenes, but the [] operator is different. With an array, [] is simple pointer math, but with a List, [] is a full-fledged method call. That's why the & isn't working: you can take the address of an array location, but you can't take the address of a value returned from a method.
Think about it like this: If they wanted to, they could change the implementation of List without changing its external interface. It would be possible to change List to store the list contents in memory gzip-compressed. In that case, stuff[0] is generated on-the-fly by the [] method which does the decompression, so there is no single memory location that contains stuff[0] to pin.
Edit
Yes, internal to the List class, the contents are contiguous in memory. You can see this in the source that Microsoft has provided. However, the List class does not make that array public: The public interface to the List class is the public methods & properties, only. The public methods & properties present a contract, and the array that the values are stored in are not part of that contract. Microsoft would never do this, but they could do a gzip-compressed implementation of List, and the public contract of the List class wouldn't change. You should only write your code to the public methods & properties of a class, not to the internals that may change at any time.

Smalltallk - How can I get an Array (or Collection) of the all the Instance variables in an Object (the current Instance) of a Class?

Let's say we have a Class and we instantiate it, creating an Instance of that Class. This Instance has a number of (instance)variables, defined by the class, that I need to use. I'd like to get all these (instance)variables in an Array or some Collection so I can iterate through them and set them to some value, not nil.
How can I do this?
I would like to build up on #Uko's answer because there is a more direct way to implement his idea.
The message instSize sent to a Class will answer the number of named instance variables of its instances. This, of course, would include instance variables defined in superclasses.
For instance, RemoteTempVectorNode instSize answers with 17 (wow!). Therefore you could do:
fields := (1 to: anObject class instSize) collect: [:i | anObject instVarAt: i]
and then, change them with:
values withIndexDo: [:v :i | anObject instVarAt: i put: v]
where values is the array of new values you want to inject into the object.
So, why I'm suggesting this instead of instVarNamed:? Because the latter is indirect. If you take a look at its implementation you will see that it has to first find out the name of the i-th ivar by sending instVarIndexFor:ifAbsent: to the object's class. In other words, if you need the ivar names, follow #Uko's suggestion; otherwise don't bring them into the equation because they will only add CPU cycles to your program.
One more thing. As #Sean DeNegris wisely raised in his comment to your question, it would be beneficial if you elaborated a little bit more on why you need such an unusual maneuver.
EDIT:
Now that Pharo has Flexible Object Layouts the mapping between inst var names and the class instSize is no longer valid (in classes that use the new capability.) So, the simpler approach of using just indexes would not work with generality. In fact, under the new "taxonomy" the instSize (number of fields) of an object may be different from the #numberOfInstanceVariables. I guess that the added flexibility has its costs and benefits.
You can send #allInstVarNames to a class (Behavior) to get names of all instance variables defined by it and by superclasses. If you need without superclass variables, you can use #instVarNames
Let's say that var is your variable that you need to work with. Then you can get the collection of instance variable names and iterate them.
You can use #instVarNamed:put: to set instance variable by name, and #instVarNamed: to get the value by name (in case you need).
I think that something like this may help you:
var class allInstVarNames do: [ :instVarName |
var instVarNamed: instVarName put: <yourValue>

GPARs async functions and passing references that are being updated by another thread

I am using GPARs asynchronous functions to fire off a process as each line in a file is parsed.
I am seeing some strange behavior that makes me wonder if I have an issue with thread safety.
Let's say I have a current object that is being loaded up with values from the current row in an input spreadsheet, like so:
Uploader {
MyRowObject currentRowObject
}
Once it has all the values from the current row, I fire off an async closure that looks a bit like this:
Closure processCurrentRowObject = { ->
myService.processCurrentRowObject (currentRowObject)
}.asyncFun()
It is defined in the same class, so it has access to the currentRowObject.
While that is off and running, I parse the next row, and start by creating a new object:
MyObject currentObject = new MyObject()
and start loading it up with values.
I assumed that this would be safe, that the asynchronous function would be pointing to the previous object. However, I wonder if because I am letting the closure bind to the reference, if somehow the reference is getting updated in the async function, and I am pulling the object instance out from under it, so to speak - changing it while it's trying to work on the previous instance.
If so, any suggestions for fixing? Or am I safe?
Thanks!
I'm not sure I fully understand your case, however, here's a quick tip.
Since it is always dangerous to share a single mutable object among threads, I'd recommend to completely separate the row objects used for different rows:
final localRowObject = currentRowObject
currentRowObject = null
Closure processCurrentRowObject = { ->
myService.processCurrentRowObject (localRowObject)
}.asyncFun()