Is Array.toString() guaranteed to remain as is in ActionScript 3? - arrays

Is it fine to display the output of Array.toString() to the user, or is there a possibility that the string format could change in future versions of ActionScript 3 or other compilers?

Here's an excerpt describing Array.toString from ECMA-262, which ActionScript 3 follows very closely:
15.4.4.2
Array.prototype.toString ( ) When the toString method is called, the following steps are taken:
1. Let array be the result of calling ToObject on the this value.
2. Let func be the result of calling the [[Get]] internal method of array with argument "join".
3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
And Array.join:
15.4.4.5
Array.prototype.join (separator) The elements of the array are converted to Strings, and these Strings are then concatenated, separated by occurrences of the separator. If no separator is provided, a single comma is used as the separator. The join method takes one argument, separator, and performs the following steps:
1. Let O be the result of calling ToObject passing the this value as the argument.
2. Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
3. Let len be ToUint32(lenVal).
4. If separator is undefined, let separator be the single-character String ",".
5. Let sep be ToString(separator).
6. If len is zero, return the empty String.
7. Let element0 be the result of calling the [[Get]] internal method of O with argument "0".
8. If element0 is undefined or null, let R be the empty String; otherwise, Let R be ToString(element0).
9. Let k be 1.
10. Repeat, while k < len
a. Let S be the String value produced by concatenating R and sep.
b. Let element be the result of calling the [[Get]] internal method of O with argument ToString(k).
c. If element is undefined or null, Let next be the empty String; otherwise, let next be ToString(element).
d. Let R be a String value produced by concatenating S and next.
e. Increase k by 1.
11. Return R.
So, the default behavior is very well defined, and won't change.

It is safe to use it as it is. Array.toString() has been the same since AS3 came out.

Return value of Array.toString() is by now equal to that of Array.join().
If you are that concerned about this behaviour not changing, use Array.join() (or, to be completely pedantic, Array.join(',')) explicitly, and you'll be safe. Joining array works this way since ActionScript exists and it's absolutely unlikely that Adobe will change something to it and loose backwards compatibility (and, well, sanity).

Related

How to transform the result of an iterator into an array in Ruby

I want to know how to transform the results of an iterator into an array. I have presented two options below, and both run, but yield the result in the wrong format.
This is the result I am getting vs what is expected.
enter image description here
I am trying to transform the iterator results into an array with Array(), but it does not work.
I tried:
Block code with .keep_if methods
for if conditionals with Array() to make the transformation.
What I expect:
An array of non-negative integers. The input (l) is an array of random integers and strings.
My code options are as follows:
Option 1:
def filter_list(l)
l.delete_if {|li| li.class ==String || li<0}
puts l
end
Option 2:
def filter_list(l)
arr=[]
for i in l
if i.class == Integer && i>=0
arr1=arr.push(i)
end
end
puts Array(arr1)
end
Why don't the above options work?
Why don't the above options work?
You have a syntax error here:
Def filter_list(l)
↑
Method definitions use the def keyword with a lower-case d. What you have written here will be interpreted as a method call to a method named Def, passing filter_list(l) as an argument, i.e. that code will be interpreted as
self.Def(filter_list(l))
Which then means that Ruby is not expecting to see an end keyword.
To output the result in the expected format just use p instead of puts.
From the docs of puts
[...] If called with an array argument, writes each element on a new line. Each given object that isn't a string or array will be converted by calling its to_s method. [...]
Whereas the p method doesn't call to_s but inspect before printing the output:
For each object, directly writes obj.inspect followed by a newline to the program's standard output.
The default string representation, returned by inspect for an array, looks like your expected output.

How to change the count of a for loop during the loop

I'm trying to change the number of items in array, over which a for loop is running, during the for loop, with the objective that this changes the number of loops. In a very simplified version, the code would look something like this:
var loopArray: [Int] = []
loopArray.append(1)
loopArray.append(2)
loopArray.append(3)
loopArray.append(4)
loopArray.append(5)
for x in 0..<Int(loopArray.count) {
print(x)
if x == 4 {
loopArray.append(6)
}
}
When running this code, 5 numbers are printed, and while the number 6 is added to the Array, the loopArray.count does not seem to update. How can I make the .count dynamic?
This is a very simplified example, in the project I'm working on, appending numbers to the array depends on conditions that may or may not be met.
I have looked for examples online, but have not been able to find any similar cases. Any help or guidance is much appreciated.
sfung3 gives the correct way to do what you want, but I think there needs to be a bit of explanation as to why your solution doesn't work
The line
for x in 0..<Int(loopArray.count)
only evaluates loopArray.count once, the first time it is hit. This is because of the way for works. Conceptually a for loop iterates through the elements of a sequence. The syntax is something like
for x in s
where
s is a sequence, give it type S
x is a let constant (you can also make it a var but that is not relevant to the current discussion) with type S.Element
So the bit after the in is a sequence - any sequence. There's nothing special about the use of ..< here, it's just a convenient way to construct a sequence of consecutive integers. In fact, it constructs a Range (btw, you don't need the cast to Int, Array.count is already an Int).
The range is only constructed when you first hit the loop and it's effectively a constant because Range is a value type.
If you don't want to use Joakim's answer, you could create your own reference type (class) that conforms to Sequence and whose elements are Int and update the upper bound each time through the loop, but that seems like a lot of work to avoid a while loop.
you can use a while loop instead of a for loop.
var i = 0
while i < loopArray.count {
print(i)
if i == 4 {
loopArray.append(6)
}
i += 1
}
which prints
0 1 2 3 4 5

What is the significance of square brackets in denoting the copy destination array?

I have been getting familiar with how to slice and dice arrays/slices in Go (the actual task is to check if the first N bytes in a byte slice is a set of particular bytes).
So I have learnt how to copy bytes from a slice into an array:
var dstArray [1]byte
srcSlice := []byte{0x00}
copy(dstArray[:], srcSlice)
What puzzles my though is the necessity to write [:] at the end of dstArray in the copy call. If I omit that I get this error:
first argument to copy should be slice; have [1]byte
First of all, why does it say "should be slice"? I provide an array instead and it works just fine (with the [:] bit).
And, the main question is: why does it require the [:] bit? What is the significance of it in this context? Could the instruction be somehow misinterpreted if we omit it? Why complicate the syntax?
[:] is the shorthand of slice expression.
According to the spec:
For convenience, any of the indices may be omitted. A missing low
index defaults to zero; a missing high index defaults to the length of
the sliced operand:
a[2:] // same as a[2 : len(a)]
a[:3] // same as a[0 : 3]
a[:] // same as a[0 : len(a)]
See also: https://golang.org/ref/spec#Slice_expressions
First of all, why does it say "should be slice"?
Because this is how the API of the function is defined, go is strongly typed language, so you should provide a value of the required type.
I provide an array instead and it works just fine (with the [:] bit).
You don't provide an array, you take an array and convert it to slice by using [:] https://play.golang.org/p/TEih17eVWml
why does it require the [:] bit?
This is how you get a slice from Array to conform with the Copy API

How to use an array of functions in Swift

I have read all the posts I can find here about arrays of functions - great you can do it. I figured. But none of the posts show practically how to use them (at least not what I'm trying to do). Here's what I want - they can all take the same args, but that's not a requirement.
This article is close, and will allow me to loop through to execute each function (which meets the first goal).
https://stackoverflow.com/a/24447484/11114752
But... what if I want to execute a single function by reference?
In other words, how to call just the referenced Arity2 function - for example:
// None of these work (with or without the parameter labels)
funcs.Arity2(n: 2, S: "Fred) // value of type [MyFuncs] has no member .Arity2
funcs[Arity2](n: 2, S: "Fred") // no exact matches to call in subscript
funcs[.Arity2](n: 2, S: "Fred") // Cannot call value of non-function type...
let fn = funcs.first(where: { a whole ton of permutations here to try to match Arity2 }) -- a whole lotta frustrating nope...
Help, please! Nothing I've tried works. The pre-compiler just goes in circles making suggestions that don't pan out and it will not compile.
EDIT:
The reason for the array in the first place is that I'm going to have a quite a few functions, and I don't know what they all are in advance. Essentially, I want a plugin type of architecture. Where I can add to the list of functions (ideally within an extension of the class, but that's another problem..) and not change the processing loop that executes each function in order.
I assume you need something like
_ = funcs.first {
if case let MyFuncs.Arity2(f) = $0 {
f(2, "Fred")
return true
}
return false
}
It can be achieved in a much simpler way if you know the position of the function in the array.
Assuming you have:
func someFunc(n: Int, s: String) {
print("call \(n) \(s)")
}
var funcs = [MyFuncs.Arity2(someFunc)]
you can do:
if case .Arity2(let f) = funcs.first {
f(2, "Fred")
}
By replacing funcs.first with funcs[i] you can access the i-th index (first make sure it does exist).

Why do I need a '<' overload for an Array class?

I'm trying to add functionality to an Array class.
So I attempted to add a sort() similar to Ruby's lexicon.
For this purpose I chose the name 'ricSort()' if deference to Swift's sort().
But the compiler says it can't find an overload for '<', albeit the 'sort({$0, $1}' by
itself works okay.
Why?
var myArray:Array = [5,4,3,2,1]
myArray.sort({$0 < $1}) <-- [1, 2, 3, 4, 5]
myArray.ricSort() <-- this doesn't work.
Here's a solution that is close to what you are looking for, followed by a discussion.
var a:Int[] = [5,4,3,2,1]
extension Array {
func ricSort(fn: (lhs: T, rhs: T) -> Bool) -> T[] {
let tempCopy = self.copy()
tempCopy.sort(fn)
return tempCopy
}
}
var b = a.ricSort(<) // [1, 2, 3, 4, 5]
There are two problems with the original code. The first, a fairly simple mistake, is that Array.sort returns no value whatsoever (represented as () which is called void or Unit in some other languages). So your function, which ends with return self.sort({$0 < $1}) doesn't actually return anything, which I believe is contrary to your intention. So that's why it needs to return tempCopy instead of return self.sort(...).
This version, unlike yours, makes a copy of the array to mutate, and returns that instead. You could easily change it to make it mutate itself (the first version of the post did this if you check the edit history). Some people argue that sort's behavior (mutating the array, instead of returning a new one) is undesirable. This behavior has been debated on some of the Apple developer lists. See http://blog.human-friendly.com/swift-arrays-the-bugs-the-bad-and-the-ugly-incomplete
The other problem is that the compiler does not have enough information to generate the code that would implement ricSort, which is why you are getting the type error. It sounds like you are wondering why it is able to work when you use myArray.sort but not when you try to execute the same code inside a function on the Array.
The reason is because you told the compiler why myArray consists of:
var myArray:Array = [5,4,3,2,1]
This is shorthand for
var myArray: Array<Int> = [5,4,3,2,1]
In other words, the compiler inferred that the myArray consists of Int, and it so happens that Int conforms to the Comparable Protocol that supplies the < operator (see: https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Comparable.html#//apple_ref/swift/intf/Comparable)[1]. From the docs, you can see that < has the following signature:
#infix func < (lhs: Self, rhs: Self) -> Bool
Depending on what languages you have a background in, it may surprise you that < is defined in terms of the language, rather than just being a built in operator. But if you think about it, < is just a function that takes two arguments and returns true or false. The #infix means that it can appear between its two functions, so you don't have to write < 1 2.
(The type "Self" here means, "whatever the type is that this protocol implements," see Protocol Associated Type Declaration in https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597)
Compare this to the signature of Array.sort: isOrderedBefore: (T, T) -> Bool
That is the generic signature. By the time the compiler is working on this line of code, it knows that the real signature is isOrderedBefore: (Int, Int) -> Bool
The compiler's job is now simple, it just has to figure out, is there a function named < that matches the expected signature, namely, one that takes two values of type Int and returns a Bool. Obviously < does match the signature here, so the compiler allows the function to be used here. It has enough information to guarantee that < will work for all values in the array. This is in contrast to a dynamic language, which cannot anticipate this. You have to actually attempt to perform the sort in order to learn if the types can actually be sorted. Some dynamic languages, like JavaScript, will make every possible attempt to continue without failing, so that expressions such as 0 < "1" evaluate correctly, while others, such as Python and Ruby, will throw an exception. Swift does neither: it prevents you from running the program, until you fixed the bug in your code.
So, why doesn't ricSort work? Because there is no type information for it to work with until you have created an instance of a particular type. It cannot infer whether the ricSort will be correct or not.
For example, suppose instead of myArray, I had this:
enum Color {
case Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
var myColors = [Color.Red, Color.Blue, Color.Green]
var sortedColors = myColors.ricSort() // Kaboom!
In that case, myColors.ricSort would fail based on a type error, because < hasn't been defined for the Color enumeration. This can happen in dynamic languages, but is never supposed to happen in languages with sophisticated type systems.
Can I still use myColors.sort? Sure. I just need to define a function that takes two colors and returns then in some order that makes sense for my domain (EM wavelength? Alphabetical order? Favorite color?):
func colorComesBefore(lhs: Color, rhs: Color) -> Bool { ... }
Then, I can pass that in: myColors.sort(colorComesBefore)
This shows, hopefully, that in order to make ricSort work, we need to construct it in such a way that its definition guarantees that when it is compiled, it can be shown to be correct, without having to run it or write unit tests.
Hopefully that explains the solution. Some proposed modifications to the Swift language may make this less painful in the future. In particular creating parameterized extensions should help.
The reason you are getting an error is that the compiler cannot guarantee that the type stored in the Array can be compared with the < operator.
You can see the same sort closure on an array whose type can be compared using < like an Int:
var list = [3,1,2]
list.sort {$0 < $1}
But you will get an error if you try to use a type that cannot be compared with <:
var URL1 = NSURL()
var URL2 = NSURL()
var list = [URL1, URL2]
list.sort {$0 < $1} // error
Especially with all the syntax you can leave out in Swift, I don't see a reason to define a method for this. The following is valid and works as expected:
list.sort(<)
You can do this because < actually defines a function that takes two Ints and returns a Bool just like the sort method is expecting.

Resources