BTW, I don't quite understand the meaning of this (from V2-a118):
Does it mean that now I can write for i,j,k,l,m,n in customobj.enumerator?Revised implementation of for: Increased maximum number of variables from 2 to 19
Yes, eg,Does it mean that now I can write for i,j,k,l,m,n in customobj.enumerator?Revised implementation of for: Increased maximum number of variables from 2 to 19
Code: Select all
for x,y,z in (byref a, byref b, byref c)
=> (
a := random(1,10),
b := random(11,20),
c := random(21,30),
random(0,5)
)
msgbox x . '`n' . y . '`n' . z
msgbox 'done'
Yes, map and array enumerators don't correspond to each other's key/value preference. We just need a unified (expected) rule here. Arrays r more commonly used. Solution would be to restrict map enumerator to 2 values mode only OR 1-value for-loop to return KEY for both array and map.40. well, what about "For map enumerator to return key is quite convenient cuz value can be obtained via KEY."?
yeah! I suppose its better to re-design old and future built-in functions to have variadic params* to be the last in the parameters list.41.can be done if __Set(Name, Params, Value) { } had Value swapped over to 2nd, with Params* becoming the new variadic parameter.
VERY good explanation! So basic complaint of #34 is irrelevant (I updated OP) BUT it has a continuation! I accidentally discovered an issue: https://www.autohotkey.com/boards/viewtopic.php?p=342033#p342033
Actually I got quite a lot of real-world test files due to for every project I do have a benchmark mode. Here goes one of my mostly used json<->json test I started since AHK V2-89, with a few custom libraries. The code is permanently optimized. The current version is expected to run with AHK v118 and v119 versions only. Unlike some simple programmatically created loops to test performance, this one uses a real JSON data. It takes some time to execute. It has to be run several times to get the lowest run time - I didn't change test's outer cycle since the first version for calculated results' compatibility. (7-zip archive, https://www.7-zip.org)
Code: Select all
;6390 v2-119 (8% as slow)
;5875 v2-118
;5907 v2-116
;5750 v2-113
;6015 v2-108
;5810 v2-103
;5730 v2-102
Code: Select all
#requires AutoHotkey v2 ;doesnt work with AHK V1 or AHK V3, tries to run with any AHK V2 version
#requires AutoHotkey v2-a116 ;works with this exact AHK V2 version ONLY.
#requires AutoHotkey v2-a116 V2-a119 ;expects only this range of AHK versions.
There is no point in introducing new syntax when what we have getpos(x:=0, y:=0, w:=0, h:=0) works fine. It is not even verbose. If you skim through the link,it suggests that tuple types be used for multiple return values instead. This is the same approach that Python uses. No other language (that I could find), aside from C# and AutoHotkey even has an out parameter. Most languages even lack byref parameters. A tuple type for multiple return values would be better:getpos(out x, out y, out w, out h) syntax looks even better!
Code: Select all
(x,y,w,h) := getpos()
SetWindowPos((x,y,w,h)*)
; or
SetWindowPos(GetPos()*)
My complaint concerns #warn UseUnsetLocal.
Code: Select all
;function start:
local x:=0, y:=0, w:=0, h:=0
;...
getpos(x, y, w, h)
;x1:=x, y1:=y
;...
customfunction(14,77,0,0,x,y)
x2:=x,y2:=y
Many custom functions use byref arguments for output - sometimes its more convenient to use several output vars instead of wrapping in/out parameters in an object. Recently added mentioned guicontrol.getpos() built-in method uses up to 4 output vars.Out parameters are mostly for DllCall anyways.
Code: Select all
function(byref _c:=unset){ ;We don't need a byref output variable to be initialized here and its variadic and may be skipped as well
;if _c argument is passed we assign a value to it:
isset(_c) && _c:=1 ;or isbyref(_c)
}
I use tuples (unmodified lists) here and there in Python, the more types we could have in AHK the better! no doubt about it.iseahound wrote: ↑29 Jul 2020, 08:02https://www.autohotkey.com/boards/viewtopic.php?f=37&t=75049
Again, tuples would be nice. Barring that, an array or an object.
They have alternatives (pointers, references).Most languages even lack byref parameters.
Hmmm... Maybe you are not looking into it that hard. Object Pascal has both. Out parameter is called exactly that. As for byref, as it's called in AutoHotkey, it is often referred to as pass by reference or call-by-reference.
In agreement. But fine with AutoHotkey's objects.iseahound wrote: ↑29 Jul 2020, 08:02https://www.autohotkey.com/boards/viewtopic.php?f=37&t=75049
Again, tuples would be nice. Barring that, an array or an object.
The single advantage of an enumerator/iterator over accessing each index by its value one after another is speed.vvhitevvizard wrote: ↑29 Jul 2020, 04:37@swagfagYes, map and array enumerators don't correspond to each other's key/value preference. We just need a unified (expected) rule here. Arrays r more commonly used. Solution would be to restrict map enumerator to 2 values mode only OR 1-value for-loop to return KEY for both array and map.40. well, what about "For map enumerator to return key is quite convenient cuz value can be obtained via KEY."?
U r absolutely right here. I've just tested loop array.length {array[a_index]} vs for v in array {v} vs for k,v in array {v} using AHK V2-118. My dbg class measures average, minimum, maximum per 1 loop out of 10000 runs. Results (in microseconds per 1 cycle):
Code: Select all
;550000|550000|550000
;1. loop array.length | min:2.1 max:17.4 avg:2.3
;2. for v in array | min:1.4 max:11 avg:1.6
;3. for k,v in array | min:1.5 max:16.7 avg:1.6
Code: Select all
a:=[1,2,3,4,5,6,7,8,9,10], c:=d:=e:=_1:=_2:=0
dbg.reset()
loop(n:=10000){
dllcall('QueryPerformanceCounter', 'int64P',_1)
loop(a.length)
c+=a[a_index]
dllcall('QueryPerformanceCounter', 'int64P',_2), dbg.add("loop array.length", _1,_2)
}
loop(n){
dllcall('QueryPerformanceCounter', 'int64P',_1)
for v in a
d+=v
dllcall('QueryPerformanceCounter', 'int64P',_2), dbg.add("for v in array", _1,_2)
}
loop(n){
dllcall('QueryPerformanceCounter', 'int64P',_1)
for k,v in a
e+=v
dllcall('QueryPerformanceCounter', 'int64P',_2), dbg.add("for k,v in array", _1,_2)
}
msgbox(a_clipboard:=c "|" d "|" e "`n" dbg.dump())
;//////////////part of ww_dbg.ahk2:
class dbg{ ;v1.2
static add(_s, _a, _b){ ;add current iteration time _s:checkpoint name, _a:start time, _b:stop time
o:=dbg, d:=time.ticks2mcs(_b-_a)
;a:min,b:max,c:counter,s:sum
o.k.has(_s) ? (r:=o.k[_s], r.c++, r.s+=d, d<r.a && r.a:=d, d>r.b && r.b:=d) : o.k[_s]:={a:d,b:d,c:1,s:d}
}static dump(){ ;print profiled data
i:=0, s:=""
for k,v in this.k
s.= ++i ". " k " | " (v.c=1 ? num.p(v.a) : "min:" num.p(v.a) " max:" num.p(v.b) " avg:" num.p(v.s/v.c)) "`n"
return s
}
static reset()=>this.k:=map()
}
;//////part of ww_str_num_bin_time.ahk2
class num{ ;v1.3.4
static Decimals:=1 ;decimals for Round()
, Precision:=6 ;num length for trimming/zero padding
static p(_n){
if(i:=instr(a:=ltrim(_n,"-0"),".",1)){
p:=num.Precision, d:=num.Decimals
r:=((i=1) ? (strlen(s:=substr(a,2))-strlen(ltrim(s,"0"))+p)
: (i<=p) ? p-i+1:0) ;q should be >0: no rounding for the left part
return rtrim(rtrim(round(_n, r>d ? d:r), "0"), ".")
}
else
return round(_n) ;integer: just trim
}
}
class time{ ;v1.1.3
static ticks2mcs(_t){ ;perf counter ticks to mcs (microseconds)
;The freq of the perf counter is fixed at system boot and is consistent across all processors
;We query it upon app init and cache
static f:=0
;If the installed hardware supports a high-resolution perf counter, the retval is nonzero
(f) || dllcall("QueryPerformanceFrequency", 'int64P',f)
;To guard against loss-of-precision, we convert to microseconds *before* dividing by ticks-per-second:
return(_t*1000000/f)
}
}
True. It gives a basic idea. It might yield even greater delta cuz we measure c+=a[a_index] inside loops and loop initialization takes some time.
Code: Select all
loop(n:=10000)
loop(a.length){
dllcall('QueryPerformanceCounter', 'int64P',_1)
c+=a[a_index]
dllcall('QueryPerformanceCounter', 'int64P',_2), dbg.add("c+=a[a_index]", _1,_2)
}
Code: Select all
550000|550000|550000
1. e+=v | min:0.2 max:146.4 avg:0.29
2. d+=v | min:0.2 max:59.5 avg:0.28
3. c+=a[a_index] | min:0.3 max:358 avg:0.44
Code: Select all
Int i
Str s
AStr a
WStr w
Short h
Char c
Float f
Double d
PTR p
Int64 i64
PTRP pp, etc
Code: Select all
gp_ellipsefill(g,b, x,y,w,h)=>dllcall("gdiplus\GdipFillEllipse", 'ptr',g, 'ptr',b, 'float',x, 'float',y, 'float',w, 'float',h)
Code: Select all
gp_ellipsefill(g,b, x,y,w,h)=>dllcall("gdiplus\GdipFillEllipse", 'p',g, 'p',b, 'f',x, 'f',y, 'f',w, 'f',h)
Performance-wise, its safe to say loop and a_index addressing for objects sux. What about returning a key for for k in array? it renders 1-var mode to be not so helpful for array forcing ppl use 2-vars mode for array, but as u can see according to the tests above, for k,v in array is just a tad slower, but by doing this, we bring consistency!
I don't think so. Typically, when you use a for loop you create (and destroy) an enumerator object, and back-up and restore the loop variables. You can't index a map using a_index, in general.Performance-wise, its safe to say loop and a_index addressing for objects sux
Yeah, I have an idea how hashed indexing works for map and I try to use vanilla array over map whenever its possible, but I beg to differ for array under debate, even tho the best possible way to measure a single AHK command/expression within a script is not accurate enuf [yet], u can see for the test results, it [1-var vs 2-var mode] doesn't make much difference even for 10-members array cuz those actions r on CPP side.
Code: Select all
g:=gui.new(), f:=g.add("edit"), g.show()
msgbox(f.type)
try f.type ;Error: the value of type "Gui.Edit" has no method named "type". OH, REALLY?
catch e
msgbox(e.message)
Code: Select all
instanceOfRandomClass.DefineMethod('only_i_have_this_method', this => MsgBox())
+If the return value of the function is not needed and the function name is written at the start of the line (or in other contexts which allow a statement, such as following else or a hotkey), the parentheses can be omitted.
Try Statement
Try
{
Statements
}
now that i think about it, if adding extra special operators(eg * ^ & out) would simplify the implementation/provide more robust error detection, go for it.getpos(x:=0, y:=0, w:=0, h:=0) works fine
Ok. From a user point of view, I expect the non-static methods to be essentially pointers to func objects with bound this.instance variables(as seen in a class definition) can be considered a sort of blueprint for the AHK interpreter, so it knows what to populate __Init()'s body with.
Code: Select all
methodN:=()=>msgbox()
Code: Select all
{
"a_type":"ybt",
"a_method":"i_say_init"
"p":88
}
THIS! Thank u for ur patience to explain this. Well, for my json.dump I could add an additional loop for .base.ownmethods.if u enumerate instanceOfRandomClass.Base, u get the instance methods(again, not including any parent class').
Code: Select all
s:=""
for k,v in inst_ybt.base.ownmethods()
s.=k "|" type(v) "`n"
msgbox(a_clipboard:=s)
Code: Select all
__Init|Func
__new|Func
init|Func
Return to “AutoHotkey Development”
Users browsing this forum: No registered users and 21 guests