21... a .b is obviously invalid if a has no b property. Strings have no b property by default.
Thank u for explanation. Lines concatenation rule seems to be overmastering here. What a pity.
12... How many functions must you define in global scope, that you need to cram them onto one line?
Speaking of my style, I use macros and lambdas in other languages to shorthand stuff. For AHK, pretty much the majority of functions I have to use outside classes and yet not as closures. I find it very convenient. Example 1: 2 lines instead of ~30:
;shorten digits length with KMG, round to precision, trim. negative nums NOT SUPPORTED
numS(_n,n:=0,k:=1000)=>(n:=0+_n, s:=(n<k) ? "":((n/=k)<k) ? "K":((n/=k)<k)
? "M":((n/=k)<k) ? "G":((n/=k)<k) ? "T":((n/=k)<k) ? "P":"ERR", numP(n) . s)
Please note I had to "allocate" 2 local vars n and k in function's parameters here.
Ironically that's similar to stack frame concept. But it deprives me of discerning the fat-arrow function calls with an excessive number of parameters and/or wrong value in place of "allocated" vars.
example 2: Usage of regular function bodies with curly brackets and commands would double and even triple the lines number (aside from comments):
;get DC from the existing gui/control. 0=DC for the whole screen. gp_ReleaseDC to del
gp_DC(_h:=0)=>dllcall("GetDC", 'ptr',_h)
gp_ReleaseDC(_h, _d:=0)=>(dllcall("ReleaseDC", 'ptr',_h, 'ptr',_d))
;create a memory DC compatible with existing dc or (=0) the app's cur scr. gp_DelDC to del
gp_memDC()=>dllcall("CreateCompatibleDC", 'ptr',0)
gp_DelDC(ByRef _d)=>(dllcall("DeleteDC", 'ptr',_d), _d:="")
;Selects an obj into the specified device context (DC). it replaces the prev obj of the same type
;_d:hdc, _h:hnd to bm/brush/font/pen/region. RET:hnd to the obj being replaced
;DC can only contain one of each type of obj (bitmap, font, pen...) at a time
gp_Select(_h, _d)=>dllcall("SelectObject", 'ptr',_d, 'ptr',_h)
;we can't delete a gdiobj while it is selected into an DC!!!
gp_Del(ByRef _h)=>(dllcall("DeleteObject", 'ptr',_h), _h:="")
;_g:pGraphics, _b:pBrush, _a:StartAngle , _s:SweepAngle
gp_PieFill(_g, _b, x, y, w, h, _a, _s)=>dllcall("gdiplus\GdipFillPie", 'ptr',_g, 'ptr',_b
, 'float',x, 'float',y, 'float',w, 'float',h, 'float',_a, 'float', _s)
;_m:CombineMode: Replace=0, Intersect=1, Union=2, Xor=3, Exclude=4, Complement=5
gp_SetClipRC(_g, x,y,w,h, _m:=0)=>dllcall("gdiplus\GdipSetClipRect", 'ptr',_g, 'float',x, 'float',y, 'float',w, 'float',h, 'int',_m)
gp_GetClipRegion(_g, c:=0)=>(c:=gp_Region(), dllcall("gdiplus\GdipGetClip", 'ptr',_g, 'uint',c), c)
gp_SetClipRegion(_g, _c, _m:=0)=>dllcall("gdiplus\GdipSetClipRegion", 'ptr',_g, 'ptr',_c, 'int',_m)
gp_ResetClip(_g)=>dllcall("gdiplus\GdipResetClip", 'ptr',_g)
gp_Region(r:=0)=>(dllcall("gdiplus\GdipCreateRegion", 'ptrp',r), r) ;r=region
gp_RegionDel(_r)=>dllcall("gdiplus\GdipDeleteRegion", 'ptr',_r)
;Determines whether a specified point lies in the area that is filled
;_p:pPath, x,y:point to be tested
;_g:pGraphics that specifies a world-to-device transformation.
; =0(default)=the test is done in world coordinates; otherwise, the test is done in device coordinates.
gp_IsFilledPathPoint(_p, x,y, _g:=0, r:=0)=>(dllcall("gdiplus\GdipIsVisiblePathPoint", 'ptr',_p, 'float',x, 'float',y, 'ptr',_g, 'ptrP',r), r)
;_a:PointF array, _b:types array, _c:count, _m:fillmode. retval:path
gp_Path(_a,_b, _c, _m:=0, p:=0)=>(dllcall("gdiplus\GdipCreatePath2", 'ptr',_a, 'ptr',_b, 'int',_c, 'int',_m, 'ptrP',p), p)
gp_NewPath(_m:=0, p:=0)=>(dllcall("gdiplus\GdipCreatePath", 'int',_m, 'ptrP',p), p)
gp_ClonePath(_p, p:=0)=>(dllcall("gdiplus\GdipClonePath", 'ptr',_p, 'ptrP',p), p)
gp_DelPath(_p)=>dllcall("gdiplus\GdipDeletePath", 'ptr',_p)
gp_DrawPath(_g,_b,_p)=>dllcall("gdiplus\GdipDrawPath", 'ptr',_g, 'ptr',_b, 'ptr',_p) ;_g:pGraphics, _b:pPen, _p:pPath
gp_FillPath(_g, _b, _p)=>dllcall("gdiplus\GdipFillPath", 'ptr',_g, 'ptr',_b, 'ptr',_p) ;_b:pBrush
gp_FlattenPath(_p, _t:=1.0, _a:=0)=>dllcall("gdiplus\GdipFlattenPath", 'ptr',_p, 'ptr',0, 'float',_t) ;_t:flatness, _a:Matrix array
;and so on
local context namespace by default should be for everything inside "curly brackets" - class declaration, function body, object's members declaration member:value inside {} and so on - I do believe global-assume for => operator is irregularity. A quirk of AHK V2.
23. You can do whatever you want by overloading the __Item property.
Performance-wise its not worth it. Especially for inner loops: according to my testing (for previous v2-108) it degrades the performance by 2-5%.
Actually I gave up and just use non-zero indexing. My point 23 is to make sure all the remnants of zero indexing r removed by default.
Last edited by vvhitevvizard on 30 Jun 2020, 07:23, edited 2 times in total.
v1.1.33 and v2.0-a113 will catch the stack overflow exception and display a message. By that point, the entire call stack will have unwound, so there will be no chance of recovery.
I try to rephrase what I meant: For a script that persists for long time (days) unmanned and do some maintaining work to have the chance to terminate in a way to save some critical data or (if there is no recovery chance) at least to let the user know when-and-why it has happened by leaving some final log message/etc. After all, even just a modal msgbox with error text stating date/time and the stack overflow cause would be ok, too. Cant wait for V2-113
15... So do FileRead (with the RAW parameter) and other functions, for other types of objects. Maybe there will be other functions that return an IO object.
I just meant all the AHK built-in object creation syntax to be unified since u implemented .new method instead of new operator.
6... But incorrect code will make your program not work. Is it better to fail quickly?
It doesn't try to change or assess returned data whether it has a special meaning or not aside from stringifying it out. it expects key-value pairs of valid AHK entities (let it be even empty strings) to be returned for for key,value in obj that has __Enum property. Ofc a script programmer can stuff up as many kludges as possible to make it go thru possible errors. But claiming "I have enumerator" (cuz __Enum property has that special meaning officially documented) and failing to return an enumerable value is a flaw for a built-in object. Actually, I cant recall any other case of for-in throwing itself instead of just concluding in case no values left to enumerate.
17... I live in the real world (for some of the time), and can't recall ever encountering a need for what you describe, in AutoHotkey.
A memory region returned by outer library. Let's say we don't wanna copy it but to patch it yet using buffer-aware functions. Also, closely following the AHK V2 trend, I have an impression that exploiting binary memory regions without declaring them as a buffer object might be restricted in the future.
You are free to hate and blame, but it changes nothing.
Haha I tried. To be honest, u r a genius yet known of being extremely conservative sometimes. I still recall it took over 5 years for u to finally yield to .Count() method implementation for Array despite of multiple requests and hackery topics working around this drawback.
U might be very irritated by me but I just run risks of bumping up other ppl's pleading - voting among true AHK V2 adepts shows they don't really think commands have to be in the language: https://www.autohotkey.com/boards/viewtopic.php?f=37&t=40169
By saying that command syntax is not a payload but a burden, I do realize removing command syntax COMPLETELY is not an easy task.
PS: Thank u for ur time! And I beg ur pardon in case some of my statements r hard to understand - I'm not a native English speaker.
I've no idea what you intend by linking to my post, which explains that the example problem under discussion would have been even more problematic without the function call statement syntax.
V2-113 thank u for resolving some of the mentioned issues and quirks.
Feels good! Now it catches code leftovers including this typo of commentary following comma (, ;):
function(){
return
a:=1 ;now it warns: this line will never execute, due to Return preceeding it.
}
Having such checkups for leftovers is GREAT! In my case it did help to find some sleeping errors in code fragments that weren't finished, were forgotten and kept as is w/o yielding immediate errors at runtime.
v2-115:
max_tokens limitation. FANTASTIC! This is a milestone in AHK development. I would expect the "invalid's wheel chair" to be extended to something like 1024 tokens. But u've outdone urself! @swagfag didn't believe it would be done till AHK v3.
And the previous limitation, as I found out, was easy to bump.
Just yday (before I found new V2-115 version) I had to gather all the named html entities to an array:
pre V2-115 reacts to this: Error: Expression too complex.
I was like "cmon! its just 271 array members". So I had to split the array in two and add 5 additional lines of code:
But the limit for expressions didn't even have a workaround. The point was to increase the performance by combining expressions and branching together.
And u resolved it the best possible way!!! There is some negligible performance drop (0-2%) but tanstaafl! There ain't no such thing as a free lunch (c) Robert Heinlein.
v116 1.gosub: absolutely loved u finally got rid of .bat-style syntax remnant! And I guess 1% performance improvement since V2-115 is due to this removal of some now-irrelevant code chunks from the main runtime cycle. 2. Tendency of adding more checkups for operand types like in this update's use floating point numbers for bit-wise operations leads to easier and faster code debugging.
but its arguable for // and //= operators; we expect a quotient to be a fixed pointer number but why the divisor can't be a floating point number still? Now it flags
But this is the intention to get 4 from this equation: divisor of 2 is too small and divisor of 3 is too big.
If someone wanted a divisor to be an integer he could use round(n) (floor(n), ceil(n)) or something like that.
Well, it remains manageable - old // method can be done with floor(a/b).
After some thought, having restricted to fixed-point integers only division operator is a good move. It enables better error checking.
3.Disabled string comparison for <, >, <= and >=
Oh God! I can't even express how much I suffered from unintentional comparison of stringified numbers (not pure numbers) to stringified numbers like in
a:="150", b:="22" ;we skipped conversion of stringified digits to pure numbers here by doing a+=0, b+=0 or something
msgbox(a<b)
pre V2-116 versions return 1 (totally wrong number-wise), V2-116 returns 0 but I would expect it to flag an error at runtime cuz we do an invalid operation on 2 strings.
Edit: Well, it actually looks like now it converts strings that can be classified as numbers into pure numbers before comparison:
@lexikos Also I come up with additional suggestions (up to point 38).
Most of my previous and following points propose command name's/syntax slight changes/addons/removals and focus on bringing more uniformity to the syntax: 5, 6, 13, 15, 25, 26, 27, 29
Some others concern debugging facility extension and seem to be not so hard to implement: 2, 3, 35, 36. These, I believe, would greatly help with testing and debugging new alpha versions.
24. (bug) Concerning line continuation section start mark. https://lexikos.github.io/v2/docs/Scripts.htm#continuation If a line begins with a non-escaped open parenthesis ((), it is considered to be the start of a continuation section unless there is a closing parenthesis ()) on the same line.
That brings issues of mixing continuation section with expressions divided by continuation prefix:
In the above snippet one would expect Line 1 is completed and not connected to line 2,
Line 2 starts with an expression in parenthesis (function call with 2 args) and that expression's result used as 1st operand of && operator.
When a regular continuation section starts, it looks like
Var := "
(
Line 1 of the text.
Line 2 of the text. By default, a linefeed (`n) is present between lines.
)"
so ( of a continuation section's start mark is a solo opening or closing parenthesis and not followed by a variable or operator or other stuff we expect to be within an expression.
The current state leads to the following preprocessor printout (the same behavior with AHK v2 builds 103,108,115):
Error at line 1.
Line Text: a:=1, 0)) && a:=2
Error: missing ")"
WOW. In "Line Text" printout (b(0 disappeared! between lines 1 and 3. So AHK simply ignored leftovers that followed opening (. That's totally counter-intuitive.
Request: In order to let lines starting with an expression to co-exist with continuation sections, start mark for the latter should be considered only when its a solo parenthesis on the line. And the closing section mark to be ) or )", )', )` respectively.
25. Alternative to IsSet for undeclared classes test w/o throwing at runtime and w/o warnings at loading time. Imagine there r multiple #include commands and the script has to figure out whether a class declaration is included or not.
We don't have a preprocessor's #def .. #ifdef implemented [yet], so the current kludge I use:
;uncomment the next 2 lines with class declaration or 1 line with an object declaration
;class classname{
;}
;classname:={}
try
isset(classname) && msgbox("classname exists, type: object") ;never triggers for a class, trigger for an object
catch{
msgbox("classname exists, type: class") ;it actually triggers if class classname DOES exist
}
26. Similar to 25, ability to test whether a gui control is "destroyed" w/o throwing.
27. Naming inconsistency. Some built-in functions use Len prefix, other properties have a Length moniker. e.g. StrLen, Match.Len() vs File.Length, Array.Length. For consistency, I would prefer unified Len everywhere.
28.Callback for regexreplace. So that it would be possible to exploit a custom function instead of replace argument's string pattern.
NB: Not to confuse Callback with the existing Callout debugging facility!
Real-world use of that functionality (regexf function). Example does decimal html entities -> unicode) conversion:
30. When we assign a "text" to a gc control, AHK automatically measures its extents and resizes it accordingly. It would be logical when changing text style/etc to have the same auto-functionality. And ability to disable any autosizing at all like setting or not setting "AutoSize" attribute for gui.show().
Example (I used a snippet from a singlet class I use for miscellaneous gui utility functions). Uncomment 4th line:
g:=gui.new()
gc:=g.add("text","", s:="The quick brown fox jumps over the lazy dog.")
gc.setfont("bold")
;win.autosize(gc) ;uncomment this line
g.show("AutoSize")
class win{
static autosize(_g)=>(o:=this, win.textmeasure(_g), _g.move(,,o.tw,o.th))
;thats how AHK calculates the initial size of a text control for gui.add("text") when none is provided
;NB: (cg.getpos(,,w,h), w) is much faster: 2us vs 60us but it doesnt address all the issues
;_g:gui control object, _s:text. unset->use gc's val
static textmeasure(_g, _s:=unset){
local g,c,d,v, rc,w,h ;g:gc, c:hdc, d:font, v:tmp, rc:RECT, w,h:width,height
;hnd=0:retrieves the DC for the entire screen
o:=this, c:=dllcall("GetDC", 'ptr',g:=_g.hwnd)
;get the font based on the control itself. 0x31= WM_GETFONT. 0:the control is using the system font
(d:=(v:=sendmessage(0x31,,, ,"ahk_id" g)) ? dllcall("SelectObject", 'ptr',c, 'ptr',v):0)
;BTW, AHK gives "ButtonN" classNN for CheckBox, "ComboBoxN" for DDL
;-1:null-terminated str, 0x440:DT_CALCRECT=400|DT_EXPANDTABS=40 ;|DT_SINGLELINE=20
o.th:=dllcall("DrawText", 'ptr',c, 'str',isset(_s) ? _s:(_g.type="edit" ? _g.value:_g.text)
, 'int',-1, 'ptr',rc:=bufferalloc(16), 'uint',0x440)
o.tw:=(numget(rc,8,'int')-numget(rc,0,'int')) ;width=rc.right-rc.left
(d) && dllcall("SelectObject", 'ptr',c, 'ptr',d), dllcall("ReleaseDC", 'ptr',g, 'ptr',c)
}
}
BTW, C# has the following settings for gui controls:
31. Continuation of the previous idea. gui.add("text","xp xs+3 w45 cWhite") syntax might be handy for simple gui control layouts, but for complex ones one might wanna populate gui controls programmatically.
So having additional commands changing gc style similar to recently added gc.getpos(x,y,w,h) is reasonably necessary: gc.setpos(), gc.settextstyle( [bold/italic/other flags,size, kerning/etc]), gc.setcolor(color [,background]), gc.autosize, gc.settextalign(), gc.padding, gc.marginx, gc.marginy, etc.
IMHO, both "text string of params" and "set of methods" approaches could co-exist for a while until the former to be phased out.
32. Concerning another AHK's quirk mitigation: runtime checkup for a passed byref argument not being a variable. There is an existing IsByRef function already, but manually providing a checkup of every passed argument for being a not valid "expression" like obj.property is a pain.
Having an ability to enable/disable that check for all the byref arguments globally with 1 #warn directive would be great. If it doesn't dramatically hurt runtime performance ofc.
33. this one is a general observation concerning non-preprocessor directives system: some in form of #command, others in form of a_variable. No uniformity here.
#SingleInstance force
#KeyHistory 0
a_listlines:=0, a_iconhidden:=1, a_fileencoding:="UTF-8"
;...
Due to preprocessor's stage 2 (or more?) passes, many language statements r put into effect before the script begins running (e.g. class declarations) and there is no principal difference between most of them - some r read-only, some r put into effect only once and before runtime, but there is no unified naming convention. For example, could #hotkeymodifiertimeout be a_hotkeymodifiertimeout? Or a_listlines be #listlines? I suppose, they made this way due to AHK historically progressed by piling up more and more commands, written by different people, w/o actually following general design rules. Nowadays not having a unified system makes a learning curve more steep. Ideally, similar to other languages, only lexemes that active at the very first preprocessor's pass should have # prefix.
35. Additional debug info. To let a script know of how much time (in milliseconds) pre-processing took. It might be A_LoadingTime built-in variable denoting a tick count of reaching WinMain() of AHK interpreter and preprocessor start, A_RunTime denoting a tick count of the beginning of script's run-time.
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)
}
Every split microsecond matters: having this built-in would increase accuracy of measurements.
The reasoning of that quirk is known: object.property, being an expression, cannot receive a value directly.
Could we have some preprocessor's latent propagation of additional commands: allocating a temporary_variable for .property and committing obj.p:=temporary_variable right after the function call:
so that every variable declared as global would become utils:variable (utils_variable, whatever) for AHK's inner logic. And it is totally transparent for the code inside namespace {} brackets with AHK transparently pre-pending namespace prefix to vars/classes declaration.
And the script code located outside utils.ahk2 to address those vars/classes/functions as utils.name (utils:name, etc)
Python-like:
Declaring a namespace just for a function and also renaming it on the fly.
That would greatly help to resolve global var naming conflicts.
--------------------------- update notes 1. Please, always specify full function/method/property names b/c it has to be searchable:
Merged ControlGet/SetTab into ControlGet/ChooseIndex.
->
Merged ControlGetTab/ControlSetTab into ControlGetIndex/ControlChooseIndex.
Changed Group(De)Activate/Close to throw
->
Changed GroupActivate/GroupDeactivate/Close to throw
2. Implemented #Requires is skipped for v2-113 notes.
3. I feel like people r reluctant to upgrade. I know, for the developers, its hard to keep in mind and cover all the stuff in the update notes, but a workaround/replacement for removed/restricted/changed features should be provided whenever possible. E.g.: "for //, //= old behavior use floor(a/b)"
It would greatly help people upgrading.
--------------- docs
etc. The format is changing and scripts using this "low-level" mechanics won't be compatible with other AHK versions but it won't be compatible with future alpha versions anyway... And AHK object's layout is changing not so fast, mainly via major updates only.
Last edited by vvhitevvizard on 18 Jul 2020, 00:08, edited 18 times in total.
That's terrible, and not something I would ever want to encourage.
I just introduced u my style. Tastes may differ. It might be somewhat sub-optimal for a code shared between people or for uploading to github. But we have an interpreted scripting language here. Having ability to shorthand evaluations is great. I do miss macro system in AHK so I would manage to hide even more unnecessary redundant details. Back in late 1980ss I moved away from Microsoft compilers (C and Assembler) to Borland due to extensive macro system the latter had. And I find shorthanding of everything to be very convenient.
In the example an expression breaks into obvious distinct blocks ? "K":((n/=k)<k)? "M":((n/=k)<k)? "G":((n/=k)<k) etc. No point to break it down into 30 lines of code if I do know what this function does.
I utilize a similar method time.s() that breaks down microseconds into microseconds, milliseconds, seconds, minutes, hours, days depending on the value (e.g. "12us", "22.51ms""4.5mins", "12.2days"):
And num.P (another one from my arsenal of custom written utilities) left trim, right trim, discards non-meaningful zeroes and tackles stuff like that 0. and then shortens a float number to N most significant digits depending on its settings.
But anyways the example and request were concerning local vars declaration in fat-arrow functions.
I've no idea what you intend by linking to my post, which explains that the example problem under discussion would have been even more problematic without the function call statement syntax.
Point is the unexpected behavior mentioned by @Helgef still exists. And it considers g (37,38) as a function call with skipped arguments due to command syntax+function syntax co-existence. Once u remove command syntax from AHK, this could be parsed the right way and flagged as a warning: cuz 37 in expression (37,38) is not used (no assignment) and then the resulting g 38 expression is not used either cuz g is a variable and not a function call.
Use of the current obj.property realization has many issues. Such a pseudo-var is automatically considered by script writers to be a var and that leads to unexpected results. Same goes for byref arguments. Its easy to unintentionally put obj.property expression instead of a truly writable value. But for the dllcall case, type:="ptr*", value:=obj.property can be checked at loading time (put double-dereferencing aside), I guess.
No. You call mreq.init() directly
I suppose I don't apprehend this. mreq has a non-static member, we haven't instanciated it yet with mreq.new()
- The class has a Prototype object, on which all instances of the class are based. All methods and properties that apply to a specific instance are contained by the prototype object. This includes all properties and methods which lack the static keyword.
- The class itself is an object, containing only static methods and properties. This includes all properties and methods with the static keyword, and all nested classes. These do not apply to a specific instance, and can be used by referring to the class itself by name.
-> Error: This value of type "Class" has no method named "load".
And I would expect the same for calling a non-instanced subclass's non-static method.
For the last 3 years I used to exploit a small utility (json.dump method) I wrote and keep updating for pretty-printing out AHK's objects/arrays/maps/all the other objects.
And non static properties r not seen for obj.ownprops() until I make an instance of that class with var:=classname.new() That is expected. I liked singlets before I use some classes as a mere container now. its very handy. I use hybrids of a static class (aka singleton) and instancing being within the same class definition.
But unexpected stuff (either this or me being wrong) starts with class extensions:
1. Non-instanced class's non-static METHODS CAN BE CALLED (unexpected), yet non-static PROPERTIES CANNOT BE ACCESSED (expected).
2. In the first example, mreq.init() never returns being called from extended class and thus msgbox("2") never activates.
Also, .ownmethods() returns no methods for instanced class objects. it works for type="Class" and class.prototype, but not for instanced objects. It is expected to act the same way as .ownprops() and be effective for object's methods as well.
BTW, ybt.prototype.init() acts as expected. ybt.init() should flag an error.
Well, I had to rewrite some extended classes I made for V2-103 to make them plain singlets (non-instanced) with callbacks facilities (instead of instancing) for the time being.
vvhitevvizard wrote:
9. https://lexikos.github.io/v2/docs/objects/Gui.htm
Good thing these gui examples keep being updated here and there. Found one remnant of the prev. algo:
Code: Select all - Toggle Line numbers
MyGui.Add("Checkbox", "vMyCheckBox", "This control has no tooltip.")
, "vMyCheckBox", should be changed to a skipped parameter , ,
But it still runs on V2-a116 w/o that special warning/error. The point is one might want an exact version to be defined, or the maximum version in addition to.
Request: ability to set a range, e.g. v2.0-a103, v2.0-a107 with comma or just whitespace between version numbers.
40. Enumerators. One-parameter mode for array returns a value yet for map it returns a key.
a:=["aa","bb"]
b:=map("a","aa","b","bb")
for v in a
msgbox(v)
for v in b
msgbox(v)
For array enumerator to return value is quite convenient cuz key can be obtained via A_INDEX. It is expected that map would return value as well.
Was it made on purpose to differentiate array from map? In my opinion, both have similar access operator [] and this inconsistency with one-parameter for-loop might cause many unexpected issues. It may be too late to change this behavior, or may be not - we have this opportunity while being in an alpha stage. Such quirks will be an eternal source of frustration.
41. (bug?) Variadic function/method vs (essentially) variadic syntax __call meta-function. I express this expectation from a user point of view here.
#1 function(_a*) returns array of parameters(s) Syntax here (_a*) (OK).
documentation says: Variadic function can accept arrays
#2 __call(_a*) returns array of argument(s) nested in another array (unexpected). https://lexikos.github.io/v2/docs/Objects.htm#Meta_Functions
documentation says: __Call(Name, Params): Name:The name of the property or method, Params:An Array of parameters.
So basically accepting array as the only parameter is the same as declaring parameters list as variadic.
I used the same syntax (_a*) for name+array of parameters. It was accepted but the result is unexpected.
If I use (_a) to address array of arguments it works but the inconsistency is what makes me restless. __call should either become a regular variadic function or simply ignore * following it instead of creating a wrapping array around it. I want an agreement for all the functions/methods to have variadic syntax if they return a variable number of parameters.
;Include my json.dump utility from the 34
t:=test.new()
t.f(77)
t.c(77)
class test{
f(_a*)=>box("1:" json.dump(_a))
__call(_a*)=>box("2:" json.dump(_a))
__new()=>this
}
Sometimes continuing to the next line is adequate, or just saves time during debugging (vs. editing and restarting the script to bypass a trivial error).
I experience an issue of not being able to exit the misbehaving script on a repeating continuable error "Target control not found". Try to continue anyway? I press No. It exits the thread then creates it anew and the same error pops up again and again... I'll add an example later.
Request: To add a third button (LOL) to exit all the threads and terminate the application.
116->118 (117 was buggy due to catch(var))
I find this new load-time warning This var appears to never be assigned a value to be very useful. It finds code leftovers that would trigger at some point to a run-time error and r very hard to debug.
Issue #25 was addressed. It works and now its possible to work with interconnected classes libraries at elementary level.
Oh, and it does work slightly faster compared to V2-116.
118->119 updateFor some unknown reason it brings a dramatic slowdown for some scripts upto 8% compared to version V2-118! I use some highly optimized (performance-wise, 250 tokens expressions, machine code dllcalls for string processing) to compare AHK builds performance and it flags that something went wrong with the last update. I can provide test files I used.
I find this new load-time warning This var appears to never be assigned a value to be very useful. It finds code leftovers that would trigger at some point to a run-time error and r very hard to debug.
I believe we have to have another command to simply stop playing w/o throwing. soundstop() or something.
45. Having new load-time warning This var appears to never be assigned a value is absolutely amazing, but what about output variables like x,y,w,h in getpos(x,y,w,h)
One has to initialize them: getpos(x:=0,y:=0,w:=0,h:=0)
but these variables r used to retrieve values only and initialization is redundant here.
A preposition to add additional syntax keyword to declare output variables so as not to be checked for initialization/assignment. Something like:
44. is broken, remnant from v1 where it sets ErrorLevel or throws if inside a try(since theres no ErrorLevel in v2 anymore, throwing is all there is)
meanwhile, swallow the exception or
45. think i read somewhere ByRef was getting a rework eventually(or maybe i dreamt it?), which would render the point of introducing special syntax/operators to handle this case moot
It is similar to C# - getpos(out x, out y, out w, out h). And is actually useful when writing DllCall code as my output parameters are visibly different from my input parameters. There's no need to develop additional syntax when what we have works fine.
40.well, what about "For map enumerator to return key is quite convenient cuz value can be obtained via KEY."?
neither single parameter map mode of enumeration seems particularly useful, but of both the former is arguably more useful.
though there could be a specialized .Keys()/.Vals() method depending on what ends up staying/becoming the default
41.can be done if __Set(Name, Params, Value) { } had Value swapped over to 2nd, with Params* becoming the new variadic parameter. guess its that way currently for consistency's sake wrt the other meta functions:
ybt.init()
class ybt extends mreq{
init(){ ;it flags no errors on calling a NON-static method. add static keyword here.
mreq.init()
msgbox("2") ;it never returns here!
}
}
class mreq{
static init(){
msgbox("1")
}
}
u call ybt.init()
ahk checks if the Classybt has a static method called init
it does not
ahk checks if the Classybt's base object(mreq) has a static method called init
it does, so it calls it. result: msgbox 1
at no point are u calling ybt's instance method init. thats just how it works.
had the base class mreqnot defined any static init(), ahk would have recursively checked for a static init() every base object all the way up to Any, then it would have recursively checked again for a meta static __Call() all the way up to Any, and only then would it have thrown saying no such(init) class method exists.
44. is broken, remnant from v1 where it sets ErrorLevel or throws if inside a try(since theres no ErrorLevel in v2 anymore, throwing is all there is)
meanwhile, swallow the exception or
Good morning! yeah I wrote that point after realizing wrapping it in try/catch block feels awkward:
And the whole routine of stopping the currently playing sound by starting to play again another non-existent sound file doesn't feel right at all.
Now that AHK discerns strings from pure numbers, it could be a pure number 0 (NULL, FALSE) as a soundplay first parameter to stop playing.
Ur SoundStop() function works like a charm. It would be great to have it on C++ AHK side eventually.
45. think i read somewhere ByRef was getting a rework eventually(or maybe i dreamt it?), which would render the point of introducing special syntax/operators to handle this case moot
It would be great if AHK could trace all the byref parameter assignments inside called out functions and figure it out itself which ones should not be flagged as a warning case.
@iseahound
wrote:It is similar to C# - getpos(out x, out y, out w, out h). And is actually useful when writing DllCall code as my output parameters are visibly different from my input parameters. There's no need to develop additional syntax when what we have works fine.
thank u for comparing to C#! getpos(out x, out y, out w, out h) syntax looks even better!
That's exactly what I meant (quotation from ur link):
The out keyword causes arguments to be passed by reference. It is like the ref keyword, except that ref requires that the variable be initialized before it is passed.
Last edited by vvhitevvizard on 29 Jul 2020, 04:07, edited 1 time in total.