I'm wrote this code a long time ago and thought I understood it at that time but now I'm trying to wrap my head around how it works...
// Main.as
package {
public class Main {
public function Main() {
var fruit:Array = [];
UpdateClass.update(fruit);
trace(fruit); // Traces out the string pushed into it? How??? I think the data would've got lost...
}
}
}
// UpdateClass.as
package {
public class UpdateClass {
public static function update(array:Array):void {
array.push("haha, this is not a fruit!");
}
}
}
I just don't understand how the UpdateClass manages to update Main's fruit array? I'm thinking the data would get lost because it is not returning the new array?... When I try this with Strings and Numbers the data does get lost like expected.
I don't know what I was on when I wrote this but I would like to try and understand the logic behind this.
Thank you.
String and Number are "primitive" data types in AS3, while Array and other objects like MovieClip are "complex" or "reference" data types.
When you pass a primitive, its value is copied, so modifying that doesn't affect the original. When you pass a complex object, it's actually a reference to the object's address in memory, so your function is modifying the original object.
I'm assuming something like following when you say that the value was lost with String and Number:
// UpdateClass.as
package {
public class UpdateClass {
public static function update(num:Number):void {
num = 1;
}
}
}
The reason it was lost was because you got a reference to the original object as num. But the function update changed that reference to another Number object which contained the value '1'. This would be true for array too, if you assign another array to the passed reference like:
// UpdateClass.as
package {
public class UpdateClass {
public static function update(array:Array):void {
array = new Array();
array.push("haha, this is not a fruit!");
}
}
}
But, since you are just calling a method on the passed reference (push), 'array' still refers to the original Array and updates it.
Related
I'm trying to be notified when an array changes its content.
Through this code I'm able to notify the setting of the array, but nothing happens when a new item is inserted.
var array: MutableMap<String, List<String>> = mutableMapOf()
set(value) {
field = value
arrayListener?.notify()
}
The only thing I came up with is resetting the array to itself everytime I add, delete o edit items, like this:
array = array
I read this question How to watch for array changes? relative to Javascript, but I'd like an easier solution then creating a new object, can anyone suggest it?
Array's API is quite simple: elements can be written there and can be read from an array.
At 99% (a number without justification, read "the vast majority") array's usages people are satisfied with this simple API. It would be a shame if a simple interface with straightforward implementation was mixed with tricky functionality.
Moving to your problem, a possible approach could be create an array's wrapper
class ArrayWrapper<T> (private val array: Array<out T>,
private val onChange: () -> Unit) {
val size = array.size
fun get(index: Int): T {
return array[index]
}
fun set(index: Int, value: T) {
array[index] = value
onChange()
}
}
An example of usage:
val ints = ArrayWrapper(arrayOf(1, 2, 3)) {
println("Array has been changed")
}
You are currently only observing that a new map is assigned to array variable. Your code won't notify you if the map entry is added or removed from the map.
If you want to observe if the array is reassigned you can use an Observable delegate from Kotlin standard lib.
Note: You should rename array variable that it fits a data structure you have used.
Here is an example:
var map: MutableMap<String, List<String>> by Delegates.observable(mutableMapOf()) {
property, oldValue, newValue ->
if (oldValue != newValue) //notify that reference has changed
}
You can read about observable delegate here.
Since you want to observe changes in the map I think you should take a look at this question. It might help. To archive what you want, you'll have to extend map or create a wrapper around it which will notify you when a map entry is added or removed.
How can I add a method to a typed array like Array<MyClass>?
Consider a case where you have a typed array where it might make sense to offer a property/method to calculate a value by accessing all items of the array.
class Foo {
date: Date
}
class FooArray extends Array<Foo> {
dateInterval() {
// Some algorithm that iterates over all dates to find
// min/max
return this.reduce(..)
}
}
But something tells me that I'm going the wrong way. For example, FooArray.splice() returns the type Foo[], not FooArray, which makes total sense to me.
Can anyone point me into the right direction?
I'll provide 2 options for you
Casting
Just explicitly add the splice method to override the inherited method to return your preferred type, with casts
splice() {
let arr = super.splice();
return new FooArray(arr); // or some other way of casting
}
Alternatively, wrapping
Wrapping
class FooArray {
constructor(private arr: Foo[]) { /* maybe copy the array...? */ }
splice(start: number, end?: number) {
return new FooArray(this.arr.splice(start, end));
}
}
This way you must be explicit about what you expose, rather than mixing the inherited base class' methods that will return normal arrays. Take your pick.
I have an array myArr where I keep objects named item1, item2, item3... etc.
trace(myArr[myRandomNumber2][myRandomNumber1]); this randomly returns [object Item1], [object Item2] etc.
I need to make If statement somthing like this:
if (myArr[myRandomNumber2][myRandomNumber1] == Item7) {
//do something
}
But this doesn't work. I don't get any errors, just nothing happens. How to check current elements name?
You cannot compare two objects directly using equality operator (either == or ===). The equality operator looks to the reference address if you are using it on objects.
Each time you create a new object, your variable (or the array) holds the reference address to the newly created object.
Ofc the reference address aren't equal, that's why you are getting false result. You can compare objects in two ways, for me, the first one is preferred.
Here below is an example of an class to create objects with ;
public class MyObject {
public var name:String;
public var info:String;
public function MyObject(newName:String, newInfo:String) {
this.name = newName;
this.info = newInfo;
}
}
1. Define a custom compareTo() method,
Add the next method in your class, here in MyObject,
public function CompareTo(otherObject:MyObject):Boolean {
// check properties and compare each properties
return (this.name == otherObject.name && this.info == otherObject.info);
}
This will only return true if the properties are equal. You might use the compare operator with strings. Just expand the above with all properties. If your properties are not public, please use the getters to obtain the property values from other objects. For the current object, this. is enough.
Then in your code,
if (myArr[myRandomNumber2][myRandomNumber1].compareTo(Item7)) {
//do something
}
or
if (Item7.compareTo(myArr[myRandomNumber2][myRandomNumber1])) {
//do something
}
both does the same.
2. use the compare() method from ObjectUtil class
Please refer first to this documentation and the explanation (with example) on it.
Then check the next statement
ObjectUtil.compare(myArr[myRandomNumber2][myRandomNumber1], Item7)
This will compare both objects using the properties in the Item object. Please note that this doesn't work if you have a class as a property. You can add a depth option to the above method to do a deep comparison. Still it might be a bit inaccurate if you have polymorph objects.
The result of the above method is an integer, either -1 or 0 or 1. Please check the documentation to understand what these numbers represents. You needs the 0 because that says that the compared objects are both equal.
Then your code;
if (ObjectUtil.compare(myArr[myRandomNumber2][myRandomNumber1], Item7) == 0) {
//do something
}
That's how you can start to compare objects correctly.
By default, trace of object with undeclared toString() method writes [object ClassName] in output. So if I understand your description correctly, you can use this:
if (myArr[myRandomNumber2][myRandomNumber1] is Item7) {
//do something
}
If Item7 is not a class as it seems, and not a reference to some object stored in your array, and not an instance of such types as int, Number, String etc., then you can declare your custom comparison function to compare this objects, for example:
if(Item7.compare(myArr[myRandomNumber2][myRandomNumber1])) {
// do someting
}
And in the class of Item7:
// ...
public function compare(obj:*):Boolean {
// your logic here
}
In any other case, your code is just incorrect.
I created a simple class with one field. class Test{int value;}
If I use the "preserve references" feature and set it to "all" (i.e. both objects and arrays), then when I simply serialize an array of Test objects, it gets serialized as a JSON object with a special "$values" member with the array values, along with the expected "$id" property to preserve the array reference. That much is fine, but once again the whole thing breaks on deserialization.
Stepping through the source code, I discovered that simply because the test for "IsReadOnlyOrFixedSize" is true, it sets a flag "createdFromNonDefaultConstructor" to true, which doesn't even make any sense, because although it is a fixed size array, it is created from a default constructor, unless it considers any fixed size array constructor a non-default constructor. The bottom line is that it should be able to handle something so basic, and yet it throws this error: "Cannot preserve reference to array or readonly list, or list created from a non-default constructor".
How can I deserialize a basic array while preserving all references in JSON.NET without getting an error?
Got the same issue, I used List<T> instead of T[] to fix it.
You are most likely missing a call to ToObject(...) and a type cast.
This should work:
class Test { public int Value; }
class Program
{
static void Main(string[] args)
{
var array = new Test[2];
var instance = new Test {Value = 123};
array[0] = instance;
array[1] = instance;
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All
};
string serialized = JsonConvert.SerializeObject(array, settings);
// Explicitly call ToObject() and cast to the target type
var deserialized = (Test[]) ((JArray)JsonConvert.DeserializeObject(serialized, settings)).ToObject(typeof(Test[]));
Debug.Assert(deserialized[0].Value == 123);
}
}
Maybe the solution is very simple. It must be, but maybe I am overlooking something
I have:
public class Object {
public int pos_x;
public int pos_y;
}
Object testObject[] = new object[10]
and then somewhere in a function
testObject[1].pos_x = 1;
It force closes my app.. how? and why? What can be the cause of this.
Furthermore. Ideally I would need something like this
testObject[].add_new_object();
testobject[].remove_item(3);
can this be done?
Thank you for helping
You have allocated an array that can hold 10 objects.
You also need to allocate the objects.
I'm not sure about the language you are using - if C# you cannot use 'Object' as the class name.
First creating a custom object (the 'object' data type):
public class MyObject {
public int pos_x;
public int pos_y;
}
...fair enough, a very basic class that holds coordinates. Next you want to create an array of MyObject. To do that, you declare your array type as MyObject[] and provide an optional size:
MyObject[] myObjArray = new MyObject[10]; // this gives a zero-based array of 10 elements, from 0-9
Now, you have the task of filling the array. The most common method would be to use a counter variable that counts from 0 to 9, the same elements we have in our array:
for (int i=0; i<=9; i++)
{
myObjArray[i] = new MyObject();
// you can also assign the variables' values here
myObjArray[i].pos_x = GetNextXVal(); // get the X value from somewhere
myObjArray[i].pos_y = GetNextYVal(); // get the y value from somewhere
}
Depending on your language, I'm sure we can point you to some good tutorials, books, or other references to help you get started.
Happy coding!