Is AutoHotkey capable of defining Arrays in a zero based order? - arrays

I've often been frustrated by the fact that AutoHotkey is not a zero based language. It doesn't match well when you are translating code from other languages, or even interacting with them such as in JScript through COM ScriptControl. Even parsing DOM elements you have to account for them being zero based, it just seems that most languages have adopted zero based arrays.
Now you can declare an array and make it zero based by doing this:
arr := []
arr[0] := 1
The above works, if I asked for arr[0] it would return 1. But if I use length() method it returns 0, even though there is a value in there!
If we declare and then push():
arr := []
arr.push(3)
It's always stored starting from 1, I want this changed!
Is this possible to do?

Because AutoHotkey is a prototype OOP language (like JavaScript) you can override any function, even built in ones. Below is demonstration of overriding Array(), which according to Lexikos is an undocumented fact that it overrides defining an array as such [].
I didn't believe it possible as there are several threads on the forums asking for zero based to implemented natively, but none offered a solution. Even the thread where an override of Array() was demonstrated made no mention that this would be possible!
As a bonus, I included split() (zero based StrSplit() function), to help demonstrate further the endless possibilities of this feature.
Just to note, I haven't unit tested or implemented ever method override, it's possible I've overlooked something but I felt it was enough for a proof of concept. Further, I have no doubts that this will affect performance on large arrays, particularly because of how I implemented Length() for this demo.
x := [] ; declare empty array
x.push("Zero Based rocks!") ; push message to the array.
msgbox % x[0]
x := "" ; clear our Object
x := split("AutoHotkey with Zero Based Arrays")
msgbox % x.2 " " x.3 " " x.4 " " x.1 " " x.0
Array(prm*) {
x := {}
loop % prm.length()
x[A_Index -1] := prm[A_Index]
x.base := _Array
return x
}
split(x, dlm:="", opt:="") {
r := []
for k,v in StrSplit(x, dlm, opt)
r.push(v)
return r
}
Class _Array {
; Modified .length() to account for 0 index
length() {
c:=0
for k in this
c++
return c
}
; Modified .push() to start at 0
push(x) {
if (this.0 == "" && this.length() == 0)
return this.0 := x
else
return this[this.MaxIndex()+1] := x
}
}

Related

Go Ranged Loop Scope and Indirect Function

Can someone help enlighten me with the "why" aspect of the following surprise I had with golang loop scoping and temporary functions? Following is an excerpt reduction from some more-complex code:
package main
import ( "fmt" )
type Caller struct {
call func()
}
func printer(val int) {
fmt.Printf("the value is %v\n", val)
}
func main () {
values := []int{1,2,3}
var callers []Caller
for _,val := range values {
call := func() { printer(val) }
callers = append(callers, Caller{call})
}
for _, caller := range callers {
caller.call()
}
}
which produces the (to me) surprising outcome:
the value is 3
the value is 3
the value is 3
If I alter that code by changing the range values loop body to this:
theVal := val
call := func() { printer(theVal) }
callers = append(callers, Caller{call})
then we get the originally hoped-for result:
the value is 1
the value is 2
the value is 3
Fundamentally, one works and the other doesn't - I'm clear on that and can try to just memorize the idiom. I'm hoping for more understanding, perhaps a little life lesson in golang. What is it about scoping rules and deferred execution that means the loop variable maintains the final valid value and is submitted into every one of the temporary functions built during the loop? Why isn't the value "val" dropped into the dynamically-built func "call"? I suspect that I am confused about something fundamental. Even seeing a working version, I am not certain I will be able to avoid a trap like this in the future. If you have advice for "why" the iterated value acts like that, I'd love to hear it (and thank you in advance).
This will work for you as well. Here's the link from the FAQ.
package main
import (
"fmt"
)
type Caller struct {
call func()
}
func printer(val int) {
fmt.Printf("the value is %v\n", val)
}
func main() {
values := []int{1, 2, 3}
var callers []Caller
for _, val := range values {
var call func()
func(v int) {
call = func() {
printer(v)
}
}(val)
callers = append(callers, Caller{call})
}
for _, caller := range callers {
caller.call()
}
}
An alternate method would be to bind the current value of val to each closure as it is launched, you can store it in a new variable and then use it (the method you have done to solve it).
Just adding a val := val inside your loop would be enough to make it work (see playground)
As you mentioned:
This is because each iteration of the loop uses the same instance of the variable v, so each closure shares that single variable.
But... That might change.
The discussion "redefining for loop variable semantics" is precisely about that:
We have talked for a long time about redefining these semantics, to make loop variables per-iteration instead of per-loop.
That is, the change would effectively be to add an implicit "x := x" at the start of every loop body for each iteration variable x, just like people do manually today.
Making this change would remove the bugs from the programs above.
Possibly for Go 1.30, with lots of warning in the meantime)
To make the breakage completely user controlled, the way the rollout would work is to change the semantics based on the go line in each package’s go.mod file, the same line we already use for enabling language features (you can only use generics in packages whose go.mod says “go 1.18” or later).
Just this once, we would use the line for changing semantics instead of for adding a feature or removing a feature.
This is still actively discussed though.

Aliasing of slices

How to check whether two slices are backed up by the same array?
For example:
a := []int{1, 2, 3}
b := a[0:1]
c := a[2:3]
alias(b, c) == true
How should alias look like?
In general you can't tell if the backing array is shared between 2 slices, because using a full slice expression, one might control the capacity of the resulting slice, and then there will be no overlap even when checking the capacity.
As an example, if you have a backing array with 10 elements, a slice may be created that only contains the first 2 elements, and its capacity might be 2. And another slice may be create that only holds its last 2 elements, its capacity again being 2.
See this example:
a := [10]int{}
x := a[0:2:2]
y := a[8:10:10]
fmt.Println("len(x) = ", len(x), ", cap(x) = ", cap(x))
fmt.Println("len(y) = ", len(y), ", cap(y) = ", cap(y))
The above will print that both lengths and capcities of x and y are 2. They obviously have the same backing array, but you won't have any means to tell that.
Edit: I've misunderstood the question, and the following describes how to tell if (elements of) 2 slices overlap.
There is no language support for this, but since slices have a contiguous section of some backing array, we can check if the address range of their elements overlap.
Unfortunately pointers are not ordered in the sense that we can't apply the < and > operators on them (there are pointers in Go, but there is no pointer arithmetic). And checking if all the addresses of the elements of the first slice matches any from the second, that's not feasible.
But we can obtain a pointer value (an address) as a type of uintptr using the reflect package, more specifically the Value.Pointer() method (or we could also do that using package unsafe, but reflect is "safer"), and uintptr values are integers, they are ordered, so we can compare them.
So what we can do is obtain the addresses of the first and last elements of the slices, and by comparing them, we can tell if they overlap.
Here's a simple implementation:
func overlap(a, b []int) bool {
if len(a) == 0 || len(b) == 0 {
return false
}
amin := reflect.ValueOf(&a[0]).Pointer()
amax := reflect.ValueOf(&a[len(a)-1]).Pointer()
bmin := reflect.ValueOf(&b[0]).Pointer()
bmax := reflect.ValueOf(&b[len(b)-1]).Pointer()
return !(amax < bmin || amin > bmax)
}
Testing it:
a := []int{0, 1, 2, 3}
b := a[0:2]
c := a[2:4]
d := a[0:3]
fmt.Println(overlap(a, b)) // true
fmt.Println(overlap(b, c)) // false
fmt.Println(overlap(c, d)) // true
Try it on the Go Playground.
Found one way of this here. The idea is that while I don't think there's a way of finding the beginning of the backing array, ptr + cap of a slice should[*] point to the end of it. So then one compares the last pointer for equality, like:
func alias(x, y nat) bool {
return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
}
[*] The code includes the following note:
Note: alias assumes that the capacity of underlying arrays is never changed for nat values; i.e. that there are no 3-operand slice expressions in this code (or worse, reflect-based operations to the same effect).

How to create a matrix in OCaml?

I'am learning OCaml and currently i'am trying to undertand how iteration works in OCaml and how to create a matrix. I want an array 5 x 5 filled with 0. I know there is an issue with shared references so i created a new array at each iteration however iam having issues in other places, specifically at line 6. Let me know of other issues like indentation practices.
open Array;;
let n = ref 5 and i = ref 0 in
let m = Array.make !n 0 in
while !i < !n do
m.(!i) <- Array.make !n 0;;
i := !i + 1;;
done
m;;
You are using ;; too much. Contrary to popular belief, ;; is not part of ordinary OCaml syntax (in my opinion anyway). It's just a special way to tell the toplevel (the REPL) that you want it to evaluate what you've typed so far.
Leave the ;; after open Array. But change all but the last ;; to ; instead.
(Since you reference the Array module by name in your code, which IMHO is good style, you can also just leave out the open Array;; altogether.)
You want the last ;; because you do want the toplevel to evaluate what you've typed so far.
Your syntax error is caused by the fact that your overall code is like this
let ... in
let ... in
while ... do
...
done
m
The while is one expression (in OCaml everything is an expression) and m is another expression. If you want to have two expressions in a row you need ; between them. So you need ; after done.
You also have a type error. When you create m you're creating an array of ints (your given initial value is 0). So you can't make it into a matrix (an array of arrays) later in the code.
Also (not trying to overload you with criticisms :-) this code reads like imperative code. It's not particularly idiomatic OCaml code. In most people's code, using ref is pretty rare. One immediate improvement I see would just be to say let n = 5. You're not changing the value of n anywhere that I see (though maybe this is part of a larger chunk of code). Another improvement would be to use for instead of while.
Finally, you can do this entire operation in one function call:
let n = 5 in
let m = Array.init n (fun i -> Array.make n 0) in
m
Using explicit loops is actually also quite rare in OCaml (at least in my code).
Or you could try this:
let n = 5 in
let m = Array.make_matrix n n 0 in
m

Is there an array version of $1...$NF in awk?

Consider the following function which is currently in the public domain.
function join(array, start, end, sep, result, i)
{
if (sep == "")
sep = " "
else if (sep == SUBSEP) # magic value
sep = ""
result = array[start]
for (i = start + 1; i <= end; i++)
result = result sep array[i]
return result
}
I would like to use this function join contiguous columns such as $2, $3, $4 where the start and end ranges are variables.
However, in order to do this, I must first convert all the fields into an array using a loop like the following.
for (i = 1; i <= NF; i++) {
a[i] = $i
}
Or the shorter version, as #StevenPenny mentioned.
split($0, a)
Unfortunately both approaches require the creation of a new variable.
Does awk have a built-in way of accessing the columns as an array so that the above manual conversions are not necessary?
No such array is defined in POSIX awk (the only array type special variables are ARGV and ENVIRON).
None exists in gawk either, though it adds PROCINFO, SYMTAB and FUNCTAB special arrays. You can check all the defined variables and types at runtime using the SYMTAB array (gawk-4.1.0 feature):
BEGIN { PROCINFO["sorted_in"]="#ind_str_asc" } # automagic sort for "in"
{ print $0 }
END { for (ss in SYMTAB) printf("%-12s: %s\n",PROCINFO["identifiers"][ss],ss) }
(though you will find that SYMTAB and FUNCTAB themselves are missing from the list, and missing from --dump-variables too, they are treated specially by design).
gawk also offers a few standard loadable extensions, none implements this feature though (and given the dynamic relation ship between $0, $1..., NF and OFS, an array that had the same functionality would be a little tricky to implement).
As suggested by Jidder, one work-around is to skip the array altogether and use fields. There's nothing special about the field names, a variable $n can be used the same as a literal like $1 (just take care to use braces for precedence in expressions like $(NF-1). Here's an fjoin function which works on fields rather than an array:
function fjoin(start,end,sep, result,ii) {
if (sep=="") sep=" "
else if (sep==SUBSEP) sep =""
result=$start
for (ii=start+1; ii<=end; ii++)
result=result sep $ii
return result
}
{ print "2,4: " fjoin(2,4,":") }
(this does not treat $0 as a special case)
Or just use split() and be happy, gawk at least guarantees that it behaves identically to field splitting (assuming that none of FS, FIELDWIDTHS and possibly IGNORECASE are being modified so as to change the behaviour).
this is what i do in my own code
function iter0gen() {
PROCINFO["sorted_in"] = "#ind_num_asc"; # skip this for mawk
return split(sprintf("%0"(NF)"d", 0), iter0, //)
}
since splitting by null string means 1-char per bin, then just split a string of zeros with length equal to that of NF, create an array called iter0, then you can do
for (x in iter0) { $(x) = do stuff….. }
This is only for if you need a lazy iterator. The plus side of this is that since indices begin at 1 by default, u can't accidentally get $0 in the iterator loop. The down side of this is that if you're not careful, you would've switched all the input FS into OFS the moment you assign into any field, and this doesn't pre-backup $0 on ur behalf.
if you just want the columns, then just do standard split() of the array using FS. If you're using gawk and would like the seps array too, then add that optional 4th argument that's non-portable.

Dynamically initialize array size in go

I try to write a small application in go that takes 'x' numbers of integers from standard input, calculates the mean and gives it back. I have only gotten so far:
func main() {
var elems, mean int
sum := 0
fmt.Print("Number of elements? ")
fmt.Scan(&elems)
var array = new([elems]int)
for i := 0; i < elems; i++ {
fmt.Printf("%d . Number? ", i+1)
fmt.Scan(&array[i])
sum += array[i];
}............
When trying to compile this I get the following error message:
invalid array bound elems
What is wrong here?
You should use a slice instead of an array:
//var array = new([elems]int) - no, arrays are not dynamic
var slice = make([]int,elems) // or slice := make([]int, elems)
See "go slices usage and internals". Also you may want to consider using range for your loop:
// for i := 0; i < elems; i++ { - correct but less idiomatic
for i, v := range slice {
In my opinion, this results from confusion over the usage of the new and make functions. This is a known issue/feature in the Go language, as evidenced by several discussions about new vs make at golang-nuts.
The difference between new and make may become clearer by letting Go print out the type of the value created by new and make:
package main
import "fmt"
func main() {
fmt.Printf("%T %v\n", new([10]int), new([10]int))
fmt.Printf("%T %v\n", make([]int, 10), make([]int, 10))
}
The output:
*[10]int &[0 0 0 0 0 0 0 0 0 0]
[]int [0 0 0 0 0 0 0 0 0 0]
As can be seen from the type, to access an array element of new([10]int) we would first need to dereference the pointer.
Both new and make require a Go type as their 1st argument. However, the expression [elems]int is not a Go type (unless elems is a Go constant, which isn't the case here).
For further reference, see http://golang.org/doc/go_spec.html#Allocation and http://golang.org/doc/go_spec.html#The_zero_value.
To get a better understanding of whether the result of new is usable, it may be helpful to lookup whether len and cap work with zero (nil) values: http://golang.org/doc/go_spec.html#Length_and_capacity
See The Go Programming Language Specification
http://golang.org/ref/spec#Array_types
http://golang.org/ref/spec#Constants
It says:"The length is part of the array's type; it must evaluate to a non- negative constant representable by a value of type int. "
Constants by no means vary.

Resources