Updated to v2-a136. [list of 51 suggestions]

Discuss the future of the AutoHotkey language
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

30 Jun 2020, 04:47

@lexikos
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:

Code: Select all

;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):
Example of GDI+ callouts

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.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

30 Jun 2020, 05:57

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.
:thumbup:
lexikos wrote:
29 Jun 2020, 23:08
16... I have no idea what you're talking about.
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.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

30 Jun 2020, 16:42

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.
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)
That's terrible, and not something I would ever want to encourage.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

15 Jul 2020, 19:36

@lexikos

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 (, ;):

Code: Select all

	a:=bufferalloc(d,0), ;commentary
, ,

Code: Select all

gp_setimage(_h.hwnd, hbm), ,gp_del(hbm)
Also I realized (since V2-103) now it warns about premature return that leaves some function's body code unconditionally never executed:

Code: Select all

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:
271 members array declaration
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:

Code: Select all

			if(uz.length<250){
				loop(z.length)
					uz.push(z[a_index])
				z:=""
			}
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. :clap:
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

Code: Select all

10//2.5
as

Code: Select all

Error: Expected Integer but not a Float
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. :thumbup:

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

Code: Select all

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:

Code: Select all

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)
outputs: 1. So stringified numbers comparison is always correct.

I've edited the opening post and hid under spoilers the points that got resolved.
Last edited by vvhitevvizard on 16 Jul 2020, 08:48, edited 26 times in total.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

15 Jul 2020, 20:02

@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:

Code: Select all

a:=1
(b(0
, 0)) && a:=2
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

Code: Select all

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):

Code: Select all

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:

Code: Select all

;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:

Code: Select all

s:="&#1088;&#1072;&#1079;&#1086;&#1073;&#1088;&#1072;&#1090;"
o:=str.regexf(s, '(?:&#(\d+);)', (_m)=>chr(_m[1]), c)
msgbox(s "`n->`n" o "`nReplaced <" c "> times")

class str{
	;RegExReplace with callback. _s:haystack, _q:needle, _f:replace func, _c:cnt
	static regexf(_s, _q, _f, byref _c:=unset){ 
		n:=1, s:="", c:=0
		while(i:=regexmatch(_s, _q, m, n))
			c++, s.=substr(_s, n, i-n) %_f%(m), n:=i+m.len(0)
		isset(c) && _c:=c
		return s substr(_s, n)
	}
}
29. Addition of FileWrite (symmetrical to FileRead). Well, or removal of FileRead. Commands set should be consistent: writes mirror reads.

Code: Select all

d:=fileopen(_s, "W"), n:=d.rawwrite(b), d.close()
->

Code: Select all

n:=FileWrite(b, "Raw")
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:
text width auto-resizing example
BTW, C# has the following settings for gui controls:

Code: Select all

Button.AutoSize=true;
Button.AutoSizeMode=GrowAndShrink;
Button.TextAlign=Left;
Button.Padding=new Padding(0, 0, 0, 0);
etc

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.

Code: Select all

#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.

34. (bug?). Extended class's method w.o static keyword acts unexpected

Code: Select all

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")
	}
}
There r more quirks concerning this matter. In the post https://www.autohotkey.com/boards/viewtopic.php?p=342033#p342033 I share a very useful utility I use for long time to test object-related stuff.

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.

Code: Select all

msgbox("preprocessing took " A_LoadingTime-A_RunTime " ms")
It would be a good instrument for assessing the interpreter's and script's code preprocess-time optimizations within a script.

36. Alternative to A_TickCount returning microseconds. A_TickCountExt? A_McsCount?

Code: Select all

dllcall('QueryPerformanceCounter', 'int64P',c:=0)
and converting ticks to microseconds by:

Code: Select all

	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.

37. object.property use for dllcall.
a) working:

Code: Select all

dllcall("some_dll_function", 'ptr',obj.p:=0)
b) syntax allowed but not working (obj.p silently fails, does not receive the output value):

Code: Select all

dllcall("another_dll_function_receiving_pointer_to_a_pointer", 'ptrP',obj.p:=0)
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:

Code: Select all

obj.p:=0
dllcall("dll_function", 'ptrp',obj.p)
at runtime translates into

Code: Select all

obj.p:=0
dllcall("dll_function", 'ptrp',tmpN)
obj.p:=tmpN
Before such an implementation, dllcall should flag an error for 'ptrP',obj.p.

38. a namespace management syntax ideas
PHP-like: declaring globals inside the included file as belonging to namespace utils:

Code: Select all

namespace utils{
#include utils.ahk2
}
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:

Code: Select all

#from utils.ahk2 #import function_name #as fn
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
9. (fixed)
10. (fixed)
11. obj.HasProp: returns true if the value has a property by this name, otherwise false
https://lexikos.github.io/v2/docs/objects/Any.htm#HasProp
obj.HasOwnProp: returns true if the object owns a property by this name, otherwise false.
https://lexikos.github.io/v2/docs/objects/Object.htm#HasOwnProp
To add an explanation of the difference (by Helgef): HasOwnProp returns true if the object owns it, HasProp returns true if it or one of its bases owns it.

12. https://lexikos.github.io/v2/docs/Objects.htm#ObjPtr
The current object structure detailed explanation (offset/description).

Code: Select all

0	vTbl pointer
8	mRefCount
;...
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.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

15 Jul 2020, 20:38

@lexikos
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"):

Code: Select all

	static s(_n,n:=0,k:=1000,m:=60,h:=24)=>(n:=0+_n, s:=(n<k) ? "us":((n/=k)<k) ? "ms":((n/=k)<m) 
		? "sec":((n/=m)<m) ? "min":((n/=m)<h) ? "hrs":(n/=h, "days"), num.p(n) s)
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.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 00:45

34. (bug?)
No. You call mreq.init() directly, you never call ybt.prototype.init()
37. B
There is no silent failure, you just disregard any output.

Cheers.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 00:54

@Helgef
Good morning! thx for quick reply!
37. just disregard any output.
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()

Code: Select all

msgbox(mreq.v) ;error: the value of type "Class" has no property named "v"
class mreq{
	v:=77
}
why it flags no errors for class's extension?
Last edited by vvhitevvizard on 16 Jul 2020, 03:25, edited 1 time in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 01:36

objects wrote: each class consists of two parts:

- 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.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 02:04

But it doesn't explain why non-instanced subclass's non-static method can be called directly.
That's what expected:

Code: Select all

mreq.load()
class mreq{
	load(){
		msgbox("3")
	}
}
-> 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.

Code: Select all

class json{ ;VER 1.9 16/07/2020 | REQ num | AHK v2-116
	;1) 0=enable indentation and line feed, 1=the most compact representation:
	;2) spaces per level, similar to JavaScript's JSON.stringify() 'space' parameter
		;JSON array elements and object members will be pretty-printed with the indent level
	static Compact:=0, Space:=4
		, Opt:=2 ;[1|2] bits: 1=throw "Not an enumerable object of type X", 2=add "a_type" pseudo-prop for any special obj

	;"stringify":obj to JSON str->str:=json.dump(obj)
	static dump(_o, _d:=""){ ;_o:obj, _d:cur indent
		static q:='"', p, t
		o:=json, isset(p) || t:=T(p:=o.Space), (o.Compact) ? n:=d:="":(n:="`n", d:=_d t), varsetstrcapacity(s,1024*8)
		y:=type(_o), y=="Array" ? a:=0 : y=="Object" ? a:=1:a:=2, (o.Opt&2 && a>1) && s.=d q "a_type" q ":" q y q "," n
		try{
			if(o.Opt&2)
				for k,v in _o.ownmethods()
					s.=d q "a_method" q ":" q k q n
			for k,v in (_o.hasmethod("__Enum") ? _o:_o.ownprops())
				s.=d (a ? q k q ":":"") (isobject(v) ? o.dump(v, d) ;recursive
					: ((b:=type(v))=="String") ? q v q : (b=="Float") ? num.t(v):v) "," n ;=Format("{:g}",v)
		}catch e
			(o.Opt&1) && o.E("Not an enumerable object of type <" y ">" (isobject(e) ? " | " e.message:"")) ;string | number | comobj | etc
		return((a ? "{":"[") (s ? (n rtrim(s, "," n) n _d) : "") (a ? "}":"]")) ;wrap in brackets
		T(n)=>--n ? T(n) " ":"" ;expand tab to spaces
	}
	static E(_s){
;		log.E(s:="JSON parser | " _s,2)
		throw({message:s})
	}
}
class num{  ;v1.3.4
	static Decimals:=1 ;decimals for Round()
	static t(_n)=>rtrim(rtrim(round(_n, num.Decimals), "0"), ".")
}

;////////tests/////////

msgbox(json.dump(ybt))
msgbox(json.dump(mreq))
inst_mreq:=mreq.new()
msgbox(json.dump(inst_mreq))
inst_ybt:=ybt.new()
msgbox(json.dump(inst_ybt))

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!
	}
	p:=88
	__new(){
	}
}
class mreq{
	static init(){
		msgbox("1")
	}
	v:=77
	load(){
		msgbox("3")
	}
	__new(){
	}
}
output: ybt class properties/methods (returned by .ownmethods/.ownprops):

Code: Select all

{
   "a_type":"Class",
   "Prototype":{
      "a_type":"Prototype",
      "__Class":"ybt",
      "a_method":"__Init"
      "a_method":"__new"
      "a_method":"init"
   },
   "a_method":"__Init"
}
output: instanced ybt class properties/methods (returned by .ownmethods/.ownprops):

Code: Select all

{
   "a_type":"ybt",
   "p":88,
   "v":77
}
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.
User avatar
Ragnar
Posts: 611
Joined: 30 Sep 2013, 15:25

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 08:27

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 , ,
Fixed via PR #443.
vvhitevvizard wrote: 10. https://lexikos.github.io/v2/docs/objects/File.htm#Length
Search for "length method". Its called "Length Method (File object)" instead of Length Property
Fixed via PR #439. This error also exists in the v1 docs.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated from v2-108 to v2-112. Just a bliss! Feels so good. But a [list of bugs/suggestions]

16 Jul 2020, 08:33

:thumbup:

17/07/2020. Updated the opening post and also added more points (up to 42).

39. #requires
I can't apprehend what syntax is required to make some special script version run ONLY with the exact alpha version. I tried

Code: Select all

#Requires AutoHotkey v2.0-a103
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.

Code: Select all

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

Code: Select all

substrings := ["one", "two", "three"]
MsgBox Join("`n", substrings*)
#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.

Code: Select all

;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
}
output 1:

Code: Select all

1:[
   77
]
output 2:

Code: Select all

2:[
   "c",
   [
      77
   ]
]

42.
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.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated to v2-119. Just a bliss! Feels so good. But a [list of 42 suggestions]

27 Jul 2020, 05:17

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. :clap:
Issue #25 was addressed. It works and now its possible to work with interconnected classes libraries at elementary level. :thumbup:
Oh, and it does work slightly faster compared to V2-116.

118->119 update For 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.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Updated to v2-119. Just a bliss! Feels so good. But a [list of 42 suggestions]

27 Jul 2020, 05:55

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. :clap:
Same!
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated to v2-119. Just a bliss! Feels so good. But a [list of 42 suggestions]

28 Jul 2020, 08:54

43. Similar to #42, a button to unconditionally exit a parsing process after the first warning dialogue at loading time.

44.
To stop a file that is currently playing, use SoundPlay on a nonexistent filename as in this example: SoundPlay "Nonexistent.avi".
And it throws:

Code: Select all

soundplay("-1")
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:

Code: Select all

retval x,y,w,h
getpos(x,y,w,h)
or maybe some mark for function's output variables like:

Code: Select all

getpos(*x,*y,*w,*h)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Updated to v2-119. [list of 45 suggestions]

28 Jul 2020, 14:57

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

Code: Select all

SoundStop() => DllCall('winmm\mciSendString', 'Str', 'stop AHK_PlayMe', 'Ptr', 0, 'UInt', 0, 'Ptr', 0, 'UInt')
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
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Updated to v2-119. [list of 45 suggestions]

28 Jul 2020, 19:43

vvhitevvizard wrote:getpos(x:=0,y:=0,w:=0,h:=0)
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.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Updated to v2-119. [list of 45 suggestions]

28 Jul 2020, 20:11

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:

Code: Select all

__Get( Name, Params)
__Set( Name, Params, Value)
__Call(Name, Params)
34.
code
  1. u call ybt.init()
  2. ahk checks if the Class ybt has a static method called init
  3. it does not
  4. ahk checks if the Class ybt's base object(mreq) has a static method called init
  5. 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 mreq not 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.

27. agree

29. remove FileAppend, too
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Updated to v2-119. [list of 45 suggestions]

29 Jul 2020, 03:21

For some unknown reason it brings a dramatic slowdown for some scripts upto 8% compared to version V2-118!
This is not very useful information if we don't know what and how you measure this.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Updated to v2-119. [list of 45 suggestions]

29 Jul 2020, 03:36

@swagfag
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:

Code: Select all

	try soundplay("-1")
	catch e{
	}
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.

Return to “AutoHotkey Development”

Who is online

Users browsing this forum: No registered users and 36 guests