Best way to remove all elements from an ActionScript Array? - apache-flex

I'm writing an application in Flex / ActionScript and have a number of class member variables of type Array storing data.
My question is: what's the "best" way to clear out an Array object?
I noticed the ArrayCollection class has a function removeAll() which does this, but the basic Array class does not. Some possibilities I've considered are:
Iterating through the array, calling pop or shift on each element
Setting the array length to 0
Setting the member variable to a "new Array()" or "[]"

I'd say:
myArray = [ ];
That's explicit, short, and makes good use of the VM's garbage collector.
Your first alternative runs a lot of interpreted code to get the same result.
I don't know that the second does what you want; if it does, it's hacky, unclear.
The "new Array()" variant of the third alternative is just wordy, offering no advantage over an array literal. If you also write JS and use JSLint, you'll get yelled at for not using the array literal form.

I'm afraid to say but Warren Young is wrong when he said that setting the myArray = [] cause the garbage collector to pick up the array.
as you have the ability to add a reference to itself within itself, and therefore would never be collected and using up memory, especially if the array has some Sprites in the array, as they too would have the array references them and they too would never be collected.
Sly_cardinal and Richard Szalay are 100% correct. but the length parameter is not needed in Richard's.
To totally clear the array and make sure its collected by garbage then
myArray.splice(0);
myArray = null;

It depends on your context. While using Mr. Young's answer is often the most correct way to do things, it will not always work, especially if you have two variables pointing to the same array:
var foo:Array
var bar:Array
foo = bar = [ 1, 2, 3 ];
bar = [];
trace( foo ); // 1,2,3
On the other hand, if you actually empty the array manually:
var foo:Array
var bar:Array
foo = bar = [ 1, 2, 3 ];
var l:int = bar.length; // get the length FIRST!
// Otherwise bar.length will change
// while you iterate!
for( var i:int = 0; i < l; i++ )
{
bar.shift();
}
trace( foo ); // does not trace anything

If you can modify the array reference, then I would go with Warren's answer. If you need to modify the existing instance, you can also use Array.splice:
var arr : Array = [1, 2, 3, 4, 5];
arr.splice(0, arr.length);

According to this test the best way is to set length = 0

Related

Nim: How to pass an array of varying size to an argument of a foreign function calling into a .dll?

Bellow is a minimal example when wrapping the OpenAL32.dll. The foreign function alcCreateContext has the argument attrlist which takes a ptr to an array of type ALCint or nil. The issue is the array can be of different lengths depending on the amount of different flags passed in. The array should be organized as [flag, int, flag, int, ...]. How can this be accomplished in a more dynamic way allowing the inclusion of ALC_FREQUENCY for example? The array size is currently hard coded into the procedure and its nasty.
when defined(windows):
{.push cdecl, dynlib: "OpenAL32.dll", importc.}
else:
{.push importc.}
type
ALCint = cint
ALCdevice* = pointer
ALCcontext* = pointer
const
ALC_MONO_SOURCES* = 0x00001010
ALC_STEREO_SOURCES* = 0x00001011
ALC_FREQUENCY* = 0x00001007
proc alcCreateContext*(device: ALCdevice; attrlist: ptr array[0..3, ALCint]): ALCcontext
proc alcOpenDevice*(devicename: cstring): ALCdevice
const attributes = [ALC_MONO_SOURCES.ALCint, 65536.ALCint, ALC_STEREO_SOURCES.ALCint, 65536.ALCint]
discard alcOpenDevice(nil).alcCreateContext(attributes.unsafeAddr)
I experimented with openArray and other containers. Is the solution some sort of cast? This is also the workaround for getting more then 256 sounds out of OpenAL.
Answer from PMunch. Thank You.
The foreign function now wants ptr UncheckedArray[ALCint] and when passing the argument use cast[ptr UncheckedArray[ALCint]](attributes.unsafeAddr)
when defined(windows):
{.push cdecl, dynlib: "OpenAL32.dll", importc.}
else:
{.push importc.}
type
ALCint = cint
ALCdevice* = pointer
ALCcontext* = pointer
const
ALC_MONO_SOURCES* = 0x00001010
ALC_STEREO_SOURCES* = 0x00001011
ALC_FREQUENCY* = 0x00001007
proc alcCreateContext*(device: ALCdevice; attrlist: ptr UncheckedArray[ALCint]): ALCcontext
proc alcOpenDevice*(devicename: cstring): ALCdevice
const attributes = [ALC_MONO_SOURCES.ALCint, 65536.ALCint, ALC_STEREO_SOURCES.ALCint, 65536.ALCint]
discard alcOpenDevice(nil).alcCreateContext(cast[ptr UncheckedArray[ALCint]](attributes.unsafeAddr))
An array in C is simply a pointer to anywhere with one or more contiguous elements of the same type. So to pass a C array to a function you simply need to get such a pointer. Say for example you have a seq of integers then the address of the first element is a C array. Simply do mySeq[0].addr and you're good. Keep the lifecycle of the data in mind though. If Nim doesn't find any more references to the sequence then the memory will get freed. You can also manually get a pointer with create (https://nim-lang.org/docs/system.html#create%2Ctypedesc) and you can cast such pointers to ptr UncheckedArray[T] to be able to use [] on the data in Nim.

Why I cannot append a value to a structs' slice using a reference?

I Go, I assumed slices were passed by reference, but this seems to work for values
but not for the array itself. For example, If I have this struct:
l := Line{
Points: []Point{
Point{3, 4},
},
}
I can define a variable, which gets passed a reference to the struct's slice
slice := l.Points
And then if I modify it, the original struct referenced by the variable
is going to reflect those modifications.
slice[0].X = 1000
fmt.Printf(
"This value %d is the same as this %d",
slice[0].X,
l.Points[0].X,
)
This differs from the behavior of arrays which, I assume, are passed by value.
So, for example, if I had defined the previous code using an array:
l := Line{
Points: [1]Point{
Point{3, 4},
},
}
arr := l.Points
arr[0].X = 1000
fmt.Println(arr.[0].X != s.Points[0].X) // equals true, original struct is untouched
Then, the l struct wouldn't have been modified.
Now, if I want to modify the slice itself I obviously cannot do this:
slice = append(slice, Point{99, 100})
Since that would only redefine the slice variable, losing the original reference.
I know I can simply do this:
l.Points = append(l.Points, Point{99, 100})
But, in some cases, it is more convenient to have another variable instead of having
to type the whole thing.
I tried this:
*slice = append(*slice, Point{99, 100})
But it doesn't work as I am trying to dereference something that apparently is not a pointer.
I finally tried this:
slice := &l.Points
*slice = append(l.Points, Point{99, 100})
And it works, but I am not sure what is happening. Why is the value of slice not overwritten? How does append works here?
Let's dispense first with a terminology issue. The Go language specification does not use the word reference the way you are using it. Go does however have pointers, and pointers are a form of reference. In addition, slices and maps are kind of special as there's some underlying data—the array underneath a slice, or the storage for a map—that may or may not already exist or be created by declaring or defining a variable whose type is slice of T or map[T1]T2 for some type T or type-pair T1 and T2.1
We can take your usage of the word reference to mean explicit pointer when talking about, e.g.:
func f1(p *int) {
// code ...
}
and the implied pointer when talking about:
func f2(m map[T1]T2) { ... }
func f3(s []T) { ... }
In f1, p really is a pointer: it thus refers to some actual int, or is nil. In f2, m refers to some underlying map, or is nil. In f3, s refers to some underlying array, or is nil.
But if you write:
l := Line{
Points: []Point{
Point{3, 4},
},
}
then you must have written:
type Line struct {
// ... maybe some fields here ...
Points []Point
// ... maybe more fields here ...
}
This Line is a struct type. It is not a slice type; it is not a map type. It contains a slice type but it is not itself one.
You now talk about passing these slices. If you pass l, you're passing the entire struct by value. It's pretty important to distinguish between that, and passing the value of l.Points. The function that receives one of these arguments must declare it with the right type.
For the most part, then, talking about references is just a red herring—a distraction from what's really going on. What we need to know is: What variables are you assigning what values, using what source code?
With all of that out of the way, let's talk about your actual code samples:
l.Points = append(l.Points, Point{99, 100})
This does just what it says:
Pass l.Points to append, which is a built-in as it is somewhat magically type-flexible (vs the rest of Go, where types are pretty rigid). It takes any value of type []T (slice of T, for any valid type T) plus one or more values of type T, and produces a new value of the same type, []T.
Assigns the result to l.Points.
When append does its work, it may:
receive nil (of the given type): in this case, it creates the underlying array, or
receive a non-nil slice: in this case, it writes into the underlying array or discards that array in favor of a new larger-capacity array as needed.2
So in all cases, the underlying array may have, in effect, just been created or replaced. It's therefore important that any other use of the same underlying array be updated appropriately. Assigning the result back to l.Points updates the—presumably one-and-only—slice variable that refers to the underlying array.
We can, however, break these assumptions:
s2 := l.Points
Now l.Points and s2 both refer to the (single) underlying array. Operations that modify that underlying array will, at least potentially, affect both s2 and l.Points.
Your second example is itself OK:
*slice = append(*slice, Point{99, 100})
but you haven't shown how slice itself was declared and/or assigned-to.
Your third example is fine as well:
slice := &l.Points
*slice = append(l.Points, Point{99, 100})
The first of these lines declares-and-initializes slice to point to l.Points. The variable slice therefore has type *[]Point. Its value—the value in slice, that is, rather than that in *slice—is the address of l.Points, which has type []Point.
The value in *slice is the value in l.Points. So you could write:
*slice = append(*slice, Point{99, 100})
here. Since *slice is just another name for l.Points, you can also write:
l.Points = append(*slice, Point{99, 100})
You only need to use *slice if there's some reason that l.Points is not available,3 but you may use *slice if that's more convenient. Reading *slice reads l.Points and updating *slice updates l.Points.
1To see what I mean by may or may not be created here, consider:
var s []int
vs:
var s = []int{42}
The first leaves s == nil while the second creates an underlying array with the capacity to hold the one int value 42, holding the one int value 42, so that s != nil.
2It's not clear to me whether there is a promise never to write on an existing slice-array whose capacity is greater than its current length, but not sufficient to hold the final result. That is, can append first append 10 objects to the existing underlying array, then discover that it needs a bigger array and expand the underlying array? The difference is observable if there are other slice values referring to the existing underlying array.
3Here, a classic example would occur if you have reason to pass l.Points or &l.Points to some existing (pre-written) function:
If you need pass l.Points—the slice value—to some existing function, that existing function cannot change the slice value, but could change the underlying array. That's probably a bad plan, so if it does do this, make sure that this is OK! If it only reads the slice and underlying array, that's a lot safer.
If you need to pass &l.Points—a value that points to the slice value—to some existing function, that existing function can change both the slice, and the underlying array.
If you're writing a new function, it's up to you to write it in whatever manner is most appropriate. If you're only going to read the slice and underlying array, you can take a value of type []Point. If you intend to update the slice in place, you should take a value of type *[]Point—pointer to slice of Point.
Append returns a new slice that may modify the original backing array of the initial slice. The original slice will still point to the original backing array, not the new one (which may or may not be in the same place in memory)
For example (playground)
slice := []int{1,2,3}
fmt.Println(len(slice))
// Output: 3
newSlice := append(slice, 4)
fmt.Println(len(newSlice))
// Output: 4
fmt.Println(len(slice))
// Output: 3
While a slice can be described as a "fat pointer to an array", it is not a pointer and therefore you can't dereference it, which is why you get an error.
By creating a pointer to a slice, and using append as you did above, you are setting the slice the pointer points to to the "new" slice returned by append.
For more information, check out Go Slice Usage And Internals
Your first attempt didn't work because slices are not pointers, they can be considered reference types. Append will modify the underlying array if it has enough capacity, otherwise it returns a new slice.
You can achieve what you want with a combination of your two attempts.
playground
l := Line{
Points: []Point{
Point{3, 4},
},
}
slice := &l.Points
for i := 0; i < 100; i++ {
*slice = append(*slice, Point{99 + i, 100 + i})
}
fmt.Println(l.Points)
I know that this might be sacrilegious, but, for me, it is useful to think of slices
as structs.
type Slice struct {
len int
cap int
Array *[n]T // Pointer to array of type T
}
Since in languages like C, the [] operator is also a dereferencing operator, we can think that every time we are accessing a slice, we are actually dereferencing the underlying array and assigning some value to it. That is:
var s []int
s[0] = 1
Might be thought of as equivalent to (in pseudo-code):
var s Slice
*s.Array[0] = 1
That is why we can say that slices are "pointers". For that reason, it can modify its underlying array like this:
myArray := [3]int{1,1,1}
mySlice := myArray[0:1]
mySlice = append(mySlice, 2, 3) // myArray == mySlice
Modifying mySlice also modifies myArray, since the slice stores a pointer to the array and, on appending, we are dereferencing that pointer.
This behavior, nonetheless, is not always like this. If we exceed the capacity of the original array, a new array is created and the original array is left untouched.
myArray := [3]int{1,1,1}
mySlice := myArray[0:1]
mySlice = append(mySlice, 2, 3, 4, 5) // myArray != mySlice
The confusion arises when we try to treat the slice itself as an actual pointer. Since we can modify an underlying array by appending to it, we are led to believe that in this case:
sliceCopy := mySlice
sliceCopy = append(sliceCopy, 6)
both slices, slice and sliceCopy are the same, but they are not. We have to explicitly pass a reference to the memory address of the slice (using the & operator) in order to modify it. That is:
sliceAddress := &mySlice
*sliceAddress = append(mySlice, 6) // or append(*sliceAddress, 6)
See also
https://forum.golangbridge.org/t/slice-pass-as-value-or-pointer/2866/4
https://blog.golang.org/go-slices-usage-and-internals
https://appliedgo.net/slices/

how to store contetnts of a several array in a matrix in C

I am trying to store contents of different vectors in a matrix.
length of vectors are different and they are all strings. lets say:
A=["MXAA', "MXBB", "MXCC"]
B=["JJJ", "LKLKLKL"]
so the new matrix should look like the following:
C= [MXAA, MXBB, MXCC;JJJ, LKLKLKL, 0]
is the a way to do that in C?
thanks
You would need to create an array of pointers to pointer to the element type (which in your case is a pointer to char).
The problem you need to consider is that every array is different size; so I suggest you store the size of the arrays, or you will quickly end up running over the bounds of an array. This sounds a bit like a custom type.
typedef {
int n;
char **strArr;
} stringArray;
stringArray *str2d;
str2d = (stringArray*) malloc(2*sizeof(stringArray));
str2d[0].n=3;
str2d[0].strArr = (char**)malloc(3*sizeof(char*));
str2d[0].strArr[0] = "MXAA";
str2d[0].strArr[1] = "MXBB";
str2d[0].strArr[2] = "MXCC";
str2d[1].n = 2;
str2d[1].strArr = (char**)malloc(2*sizeof(char*));
str2d[1].strArr[0] = "JJJ";
str2d[1].strArr[1] = "LKLKLKL";
If you want to access an element you use similar addressing - but check that you stay within bounds!
I deliberately did this in very explicit steps, hoping this makes the principle clear. There are better ways to do this but they are more obscure (or not "standard C")

How do you emit to class that has a 'params' constructor?

Here is the definition of my Package class:
type Package ([<ParamArray>] info : Object[]) =
do
info |> Array.iter (Console.WriteLine)
member this.Count = info.Length
and here is the IL, I'm trying:
let ilGen = methodbuild.GetILGenerator()
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
but this doesn't seem to work. I tried:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<String>; typeof<String>; typeof<String>|]))
a well as:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object>; typeof<Object>; typeof<Object>|]))
but it just laughs at me. What am I doing wrong?
The [<ParamArray>] attribute indicates to a compiler that a method accepts a variable number of arguments. However, the CLR doesn't really support varargs methods -- it's just syntactic sugar provided by the C#/VB.NET/F# compilers.
Now, if you take away the [<ParamArray>], what are you left with?
(info : Object[])
That is the signature of the constructor you're trying to call.
So, you'll need to use the newarr and stelem opcodes to create an array, store the values into it, then call the constructor using the array as the argument. This should do what you want (though I haven't tested it):
let ilGen = methodbuild.GetILGenerator()
// Create the array
ilGen.Emit(OpCodes.Ldc_I4_3)
ilGen.Emit(OpCodes.Newarr, typeof<obj>)
// Store the first array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_0)
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the second array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_1)
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the third array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_2)
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Stelem_Ref)
// Call the constructor
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
NOTE: In this code, I used the dup OpCode to avoid creating a local variable to hold the array reference while storing the element values. This is only feasible because this code is fairly straightforward -- I strongly suggest you create a local variable to hold the array reference if you want to build something more complicated.

ActionScript: An equivalent of Python's `repr` (ie, a useful string representation of an object)?

Python's repr function is awesome: it returns a printable representation of an object.
For example, repr(["a'b", {1: 2}, u"foo"]) is the string '["a\'b", {1: 2}, u\'foo\']'. Notice, eg, how quotes are properly escaped.
So, is there anything like this for ActionScript?
For example, right now: [1, 2, ["3", "4"]].toString() produces the string "1,2,3,4"… Which really isn't very helpful. I'd like it to produce a string like… Well, '[1, 2, ["3", "4"]]'.
I have considered using a JSON library… But that's less than ideal, because it will try to serialize instances of arbitrary objects, which I don't really want.
AFAIK there isn't any quick-easy one line command that does what you want, but here's a way to do it, straight from Adobe I might add
http://livedocs.adobe.com/flex/3/html/help.html?content=usingas_8.html
This is the only thing remotley close:
valueOf ()
public function valueOf():Object
Language Version : ActionScript 3.0
Runtime Versions : AIR 1.0, Flash Player 9
Returns the primitive value of the specified object. If this object does not have a primitive value, the object itself is returned.
Note: Methods of the Object class are dynamically created on Object's prototype. To redefine this method in a subclass of Object, do not use the override keyword. For example, A subclass of Object implements function valueOf():Object instead of using an override of the base class.
Returns
Object — The primitive value of this object or the object itself.
You can try the ObjectUtil.toString function, it's not exatly what you want, but I don't think you will find anything closer to what you want as it's functions is described as "Pretty-prints the specified Object into a String.", which is what it does, but keeps much more info that you would want. As Array is a complex data object and that's why it annotates it like that.
var a:Array = [1, 2, ["3", "4"]];
trace (ObjectUtil.toString(a));
// returns
// (Array)#0
// [0] 1
// [1] 2
// [2] (Array)#1
// [0] "3"
// [1] "4"
I'm wondering how would repr handle this example:
var a:Array = [0,1,2];
a.push(a);
trace (ObjectUtil.toString(a));
// returns
// (Array)#0
// [0] 0
// [1] 1
// [2] 2
// [3] (Array)#0
Yes I know what you want, the solution is quite simple, use JSON object to complete it!
For example:
trace(JSON.stringify('hello'));
trace(JSON.stringify(['yet', 'another']));
trace(JSON.stringify({hello: 'world'}));
Try it!
Read more about that please visit here.

Resources