fat function in class method changes var outside itsscope

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

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 01:51

nnnik wrote:
22 Jan 2019, 02:50
AHKs classes are not their own scope - you are in global scope thats why the callback func (defined by a fat arrow) defined in global scope messes with global scope.
This is not a keyword - it's a hidden 1st parameter on any method.
U r talking of classes. but the question here is scope of methods (aka class functions) here. U cant even run a code of class scope itself - its impossible.

Code: Select all

class class1{
;try to run some code outside methods here
}
When I use static to "bind" a fat-arrow body I mean 2 things: 1) the key will be persistent to class's body and 2) it will be evaluated and assigned to the key only once.
Last edited by vvhitevvizard on 23 Jan 2019, 02:09, edited 2 times in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 01:51

it requires explicit use of () for function calls inside fat arrow expr.
All function calls require () in an expression, except as described here.
I would prefer expression evaluation tell me about if some var has a name as a built-in function instead of just failing silently.
There is no silent failure, function names aren't reserved. I do not think they should unless we have case sensitive variables and function names etc...
If I combine built-in function calls in 1 line:
f() => expr is equivalent to

Code: Select all

f(){
	return expr
}
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 01:58

Helgef wrote:
23 Jan 2019, 01:51
it requires explicit use of () for function calls inside fat arrow expr.
Helgef, u try to explain everything in terms of semantics. I share my expectation as a user of the language - every unexpected quirk adds up to negative experience for a user.
I know how expressions r evaluated in general. Tbh I would prefer the whole script to be 1 giant expression and commands like if, while, continue, etc to be evaluated inside it so I could combine them on 1 line. :D

What I try to point out is it neither accepts my syntax nor raises an error here. Im against any silent failure behavior like this one. If I want ListVars to be a var I either enclose it in brackets (Listvars) or add some operands around it ++ListVars or add function syntax to it Listvars() or assign it some value ListVars:="" or declare it local ListVars (I migth miss some use cases here but u got my idea). What the heck is ListVars here? I've done nothing of that explicitly and I don't expect AHK to take ListVars , Pause silently. Here should be any hint of error.
f() => expr is equivalent to
It was enclosed in brackets in the example =>(ListVars, Pause). So both parts devided by , r evaluated before returning.
There is no silent failure, function names aren't reserved.
But we do have a function to differ Built-in function names from UDF. So I expected this check to be inside expressions. For static names such a check should have been made at load time, right?
Last edited by vvhitevvizard on 23 Jan 2019, 04:10, edited 1 time in total.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 03:34

basically, remove command syntax
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 03:39

etc to be evaluated inside it so I could combine them on 1 line
1 line stuff like that is so disgusting.
What I try to point out is it neither accepts my syntax nor raises an error here. Im against any silent failure behavior like this one. If I want ListVars to be a var I either enclose it in brackets (Listvars) or add function syntax to it Listvars() or assign it some value ListVars:="" or declare it local ListVars (I migth miss some use cases here but u got my idea). I've done nothing of that explicitly and I don't expect AHK to take ListVars , Pause silently. Here should be any hint of error.
AHKs behaviour - regardless of the varname - is it to create the variable as soon as it's referenced. IMO it might make more sense to remove the command style call for functions so that people cannot run into this limitation anymore.
It was enclosed in brackets in the example =>(ListVars, Pause). So both parts devided by , r evaluated before returning.
Which does not make any difference in the slightest.
There is no silent failure, function names aren't reserved.
You referenced a variable - do you want a #Warn mode that tells you when you used a variable that has the same name as a function?
Recommends AHK Studio
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 03:47

swagfag wrote:
23 Jan 2019, 03:34
basically, remove command syntax
Yuppers! We want a revolution! :D
If that requires adding some parenthesis all over the script body cuz the design becomes more strict I'm ready. But the interpeter should signal all the related errors.

The majority of v2 issues branches from the efforts to remain v2 compatible to v1 as in many aspects as possible and that effectively transfers v1 quirks further on in my opinion.
Recently I returned to AHK seeing v2 becomes much more structured and logical by Lexikos efforts. tho he is conservative at the same time - enabling Count() for associative arrays/objects took him over 4 years. :D
Helgef wrote:
23 Jan 2019, 01:51
All function calls require () in an expression, except as described here[/url].
Yeah. That example of command-like syntax remaining in v2 drives me mad:
Add(2, 3)
Add 2, 3 ; Parentheses can be omitted if used at the start of a line.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 04:28

nnnik wrote:
23 Jan 2019, 03:39
1 line stuff like that is so disgusting.
Well, it doesn't imply everyone HAS to use that style. its like OTB brackets, a matter of choice. I, for one, would like to combine bracket enclosement commands (if, loop, try, etc) especially if they dont have a bracketed body. e.g.:

Code: Select all

if(a)
   b++
else
   continue
->

Code: Select all

if(a) b++, else continue
I can use short-circuit logic for some parts of it: (a) && b++, but I cant add continue to the same line

It cannot be written like this

Code: Select all

if(a)
   b++, break
break requires new line... For people like me it prevents from using screen space more effectively
AHKs behaviour - regardless of the varname - is it to create the variable as soon as it's referenced. IMO it might make more sense to remove the command style call for functions so that people cannot run into this limitation anymore.
Yes! That's what I wish with all my heart. And we have that chance with v2. We r still in alpha state and bound to radical changes and not fully interrelated to v1.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 04:43

nnnik wrote:
23 Jan 2019, 03:39
Which does not make any difference in the slightest.
yes. I just answered Helgef post where he broke down fat-arrow logic. we dont return right after first sub-expression there.
You referenced a variable - do you want a #Warn mode that tells you when you used a variable that has the same name as a function?
Not just User-Defined Function, Built-in Function! And done that w.o any assignment... Just Listvars. It should be load-time error cuz expr like this makes no sense and prolly a mistype. If we need to let AHK know we want to reference it (for free variables and other cases), it should be written as (Listvar) at least.
And #warn mode u mentioned - why not to have it? I like it. :)
Last edited by vvhitevvizard on 23 Jan 2019, 04:54, edited 1 time in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 04:50

No but adding the possibility of using that style requires work. The style itself is completely useless and has no objective value at all.
I wouldn't want anyone to waste their time even thinking about how to add it to AHK much less than I want to discuss it.
Recommends AHK Studio
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 05:03

nnnik wrote:
23 Jan 2019, 04:50
No but the possibility of using that style requires no work. The style is completely removed from anything which has any value as a style.
I don't understand. Could u rephrase please.
nnnik wrote:
23 Jan 2019, 04:50
I wouldn't want anyone to waste their time even thinking about how to add it to AHK much less I want to discuss it.
I do my best to express my personal experience and expectations. Ofc its up to the active developers to implement anything of this. But I would not even create a single post if I didn't care of the AHK future. :)

2.
nnnik wrote:
22 Jan 2019, 04:41
^I think this is what he means.
Tested it works - but dont use that please.
U effectively added argument to it. As I wrote before about that hack of allocating local vars in arguments list, u can write it directly Time(t:=0)=>... and use that t as if its a local var. But it reduces performance compared to direct declaration or straightforward usage of the var cuz it adds initialization and shadowing (redundant copying) of that var into local var with the same name. Anyways that's what I HAD to do for now to return stability to my fat-arrow lines.

3.
Helgef wrote:
22 Jan 2019, 05:16
@ OP.
Even if fat arrow was changed (back) to assume local for outside function fat arrows, since you cannot force local in fat arrow, you should always use a full function/method definition if you are going to reference any non parameter/upvar in a fat arrow, unless you really want to reference a global var. So your complaints are futile, what you really want is to ask for is full function body fat arrows, eg,
fat-arrow Func (we put aside fat-arrow Closure) should act the same way as if a full function definition is placed in its place. If the AHK developers don't want to add assume-mode change command support then yes - for irregular stuff a user would have to use full function definitions. But again - default for function body should be assume-local, no other kinky default variants. Normally global vars (upvars) should be passed via arguments to a function. Class methods should be even more encapsulated. by default. Twisty-minded users r allowed to do whatever they want with full-body declarations. Everyone is happy.
I start losing my faith cuz structured language expectations r called futile here. *sad panda face*

PS: Full function body syntax for fat arrows has no advantages - it requires curly brackets to be on a new line etc, it takes the same screen space.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

23 Jan 2019, 09:16

btw, some thoughts of binary fields (byte array) shortcomings of AHK:
https://www.autohotkey.com/boards/viewtopic.php?p=259597#p259597
coffee
Posts: 133
Joined: 01 Apr 2017, 07:55

Re: fat function in class method changes var outside itsscope

24 Jan 2019, 01:32

vvhitevvizard wrote:
23 Jan 2019, 01:58
I know how expressions r evaluated in general.
Flow control statements, keyword statements, action commands and expressions are processed in separate stages of the script. Declaration keywords are not even considered in the expression parser, so they are just variables. Only callables in expressions are functions, commands called as functions and function objects using parenthesis. Commands without function parenthesis in expressions are not considered commands, only variables, because they are not handled in the expression parser.
Non expressions statements need to appear by themselves in one line.
vvhitevvizard wrote:
23 Jan 2019, 01:58
What I try to point out is it neither accepts my syntax nor raises an error here. Im against any silent failure behavior like this one. If I want ListVars to be a var I either enclose it in brackets (Listvars) or add some operands around it ++ListVars or add function syntax to it Listvars() or assign it some value ListVars:="" or declare it local ListVars (I migth miss some use cases here but u got my idea). What the heck is ListVars here? I've done nothing of that explicitly and I don't expect AHK to take ListVars , Pause silently. Here should be any hint of error.
It's a matter of knowing what is what, commands are not functions and vice versa (but they can be converted). Not everything is an expression either, or is even handled during the evaluation of the expression, some stuff is handled well before that (directive, hotkeys, function definitions, variable declarations, etc).
listvars , pause this example throws an exception in the latest ahk_l v2 (with the space before the comma or without a space before the comma).
Listvars() this is neither a variable nor a variable with a function pointer (it is never considered a variable, it makes no attempt to see if it's a variable holding a function reference either, hence why you are forced to use .call). Anything with function call format like that, parenthesis on its right, will always trigger a function lookup. If there are no functions of that name, it will check if there are commands of that name. Unless, it's a function reference in an object. Then it will attempt to call the function held in that field, if there aren't any it is passed to the __call meta if it's defined.

Functions and variables do not share the same storage. A variable can be named like a function without breaking the function. You can also override built in functions with your own of the same name. Useful if you want to change how the Array and Object function work to set your own bases.
Objects are variables that hold the object. So by obviousness, they share the same storage. Same goes for classes, classes are objects with some QOL and some more capability, but by the end of the day, they are objects, and are held by variables.

Code: Select all

foo := 1
msgbox(foo)
msgbox(foo())
foo() {
	return 10
}
If you want to declare variables without a keyword then define them at the same time. That's just good practice, and even better practice is using the keyword, unless you are in the global scope, where ahk_l has no keyword for them.

some_name by itself in a line will either call a command, or a function, not declare a variable. They are not considered variables even if you force commands to be called with parenthesis (i.e prevent command param).

Code: Select all

mbox ; calls the function
mbox() {
	msgbox()
}
(listvars, sleep) There are no built in functions here, or commands for that matter. Only two variables.
vvhitevvizard wrote:
23 Jan 2019, 01:58
It was enclosed in brackets in the example =>(ListVars, Pause). So both parts devided by , r evaluated before returning.
Commands can't be called inside expressions, unless they are called like a function. Functions can only be called inside expressions with ().

dwasd command or function.
dwasd() function or command (or maybe even command then function, i'll have to go down that rabbit hole to confirm).
(dwasd, pause) variables.
dwasd := 0 variable declaration and definition scoped to whatever it is and will collide with superglobals.
local dwasd variable declaration, handled at the top of the line parser, local, no superglobal collision.
local dwasd, dwasd2, dwasd3 multiple variable declaration, handled at the top of the line parser, local, no superglobal collision.
local dwasd := 0 variable declaration and definition, local, no superglobal collision.
local inside a function, sets assume local for all variables, superglobals will not work unless declared using global.
(local, static, global) variables.
(local + global) expression, no keywords.

Code: Select all

local := 1
global := 1
msgbox(local + global)
local + global by itself in a line, error. Attempts function call since local + global literally means nothing. Its output is not used, none of the variables are changed, can't be an expression by itself, since there is no use for it.

Non expressions statements need to appear by themselves in one line.

Multiple expression statements can appear in one line with subexpressions or operators. Expressions can also span multiple lines when enclosed by () {} [] they will be concatenated as is (with a space for autoconcat). Some expressions can't appear at the beginning of the line or by themselves if it causes collision with other parts of the parser. 1+1 by itself will error.

Code: Select all

list := [
	"hello",
	"world"
]
msgbox(list[2])

text := (
	"what's "
	"up "
	"brother?"
)
msgbox(text)
List of current non-expressions statements and keywords (incl commands and flow control), as well as local + global, which is handled somewhere else.
Spoiler
List of functions.
Spoiler

Handholding part1
Spoiler

Handholding part2
Spoiler
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

24 Jan 2019, 06:26

coffee wrote:
24 Jan 2019, 01:32
Declaration keywords are not even considered in the expression parser, so they are just variables.
Oh One that statement of urs explains many things! Thx for ur feedback.
Functions and variables do not share the same storage. A variable can be named like a function without breaking the function. You can also override built in functions with your own of the same name.
But what do u think of using just a bare variable name in the expression? Not ( (var) ) as if we wanted to evaluate it (such syntax is currently used in AHK for evaluation of key names inside objects/array declaration), just ( var ). Especially if variable's value is not used further on in the expression (like Listvars in here): ()=>(ListVars, Pause) Shouldn't it be signaled as an error, should it?
some_name by itself in a line will either call a command, or a function, not declare a variable. They are not considered variables even if you force commands to be called with parenthesis (i.e prevent command param).
I believe the major AHK issue here we have that rudimentary command syntax. One language here, another language there. Logic inside expressions seems much more mature and logic outside pushes us back to the dark past of batch scripts.
(local, static, global) variables.
Well, w.o major overhaul of expressions parser, making an expected proper assume-mode for fat-arrow Func would fix the things. No need for local, static, etc keywords support inside expressions. Function (Func object's referenced body) should be assume-local by default, do u agree with me?
coffee
Posts: 133
Joined: 01 Apr 2017, 07:55

Re: fat function in class method changes var outside itsscope

25 Jan 2019, 00:42

vvhitevvizard wrote:
24 Jan 2019, 06:26
But what do u think of using just a bare variable name in the expression? Not ( (var) ) as if we wanted to evaluate it (such syntax is currently used in AHK for evaluation of key names inside objects/array declaration), just ( var ). Especially if variable's value is not used further on in the expression (like Listvars in here): ()=>(ListVars, Pause) Shouldn't it be signaled as an error, should it?
I'm not sure what you mean here. You don't need to use parenthesis to evaluate a variable inside an expression, or outside of one, barring that exception of object creation syntax and gosub/goto.
If you want to use an expression evaluation to simulate the declaration of multiple variables outside of any function you can readily do so. That will just create multiple variables if they don't exist.

Code: Select all

(var1, var2, var3 := 1, var4) ; These variables will continue to exist after the expression is done. The result of the expression will be value of var4, which is discarded, since there's nothing receiving it.
; If they didn't exist previously and nothing is done to them, then they simply hold an empty string.
; You can also simply chain them, no parenthesis needed.
varA := varB := varC := "", varD := 1
;or
varE := varF := varG := varH
msgbox(varG == '') ; 1

(var5, var6 := 1, var6) ; var5 is created, if not found, otherwise it's value is retrieved and discarded, but the result of the main expression is var6 evaluated, i.e 1, rightmost.
; so
var8 := (var7, 10) ; it will find or create var7, and the result, 10, will be stored in var8
var11 := (var22 := 22, var33 := var22, var44 := var33 + 1) ; var11 and var44 contain 23, all the other ones contain 22.
msgbox(var11 " | " var33 " | " var44)
Expressions can contain any number of subexpressions which are evaluated from left to right. If nothing grabs the result of the main expression, which is the result of the rightmost subexpression, then it is discarded.
I'm 99.99% positive every subexpression returns something, but you can only get the last subexpression's return value.
(aa,bb,cc,1) The subexpression aa will return whatever value variable aa has, if it doesn't exist, it's created with an empty string and returned, but since you can't cherry pick which result you want, anything non-rightmost is discarded.
vvhitevvizard wrote:
24 Jan 2019, 06:26
()=>(ListVars, Pause) Shouldn't it be signaled as an error, should it?
Why would it error? the body of a fat arrow is strictly an expression in a return statement, think of syntax sugar like classes are for objects, unlike fat arrows or function expressions in javascript for example. If you follow the rules of expressions, there are no wrongdoings, listvars or pause are just variables in that example. They are not looked up as, or considered, functions or commands. Only reserved words are flow control statements and some word operators.
https://lexikos.github.io/v2/docs/Variables.htm#comma
I think helgef already posted this but

Code: Select all

ab() => (1,2,3,4,5) ; will return 5
; is the same as, barring the scoping
ab() {
	return (1,2,3,4,5) ; key point in the parenthesis here. That's what the fat arrow *is*. A function that returns a main expression that can have any number of subexpressions.
}
The reason why (var) is used in object creation keys is because it's a workaround for evaluating variables when creating objects with {}, since unquoted keys are taken as simple text, to maintain consistency with object access. obj.key doesn't require quotes in key.

Code: Select all

var1 := "key5"
obj := {
	key1: "value1", ; looks similar to obj.key1 := "value1"
	key2: value2, ; value2 here is a variable that is evaluated. Right key values are expressions.
	key3: msgbox "hi", ; msgbox is considered a variable. Unless defined, it's empty, so "hi" is concatenated to it.
	"key4": 10, ; Quoting the key is optional unless it has a space (there may be more conditions for this).
	(var1): "value5",
	(var2): "value6" ; if var2 doesn't exist, it will retardedly be an empty string key. Variable is created and is ''.
}

msgbox(obj.key3) ; "hi" -- No need for quotes as obj."key3". Only when accessing it with square brackets.
++obj.key4 ; No need for quotes.
msgbox(obj["key4"]) ; 11
msgbox(obj.key5) ; value5 -- Can also do obj[var1], no need to enclosre var1 in parenthesis.
msgbox(obj['']) ; value6 -- Only way to access empty string key is with square brackets.
vvhitevvizard wrote:
24 Jan 2019, 06:26
I believe the major AHK issue here we have that rudimentary command syntax. One language here, another language there. Logic inside expressions seems much more mature and logic outside pushes us back to the dark past of batch scripts.
For commands yes, I don't like command "calling" either which is why I disabled that in my setup. For other statements you can't do that since you have no mandatory delimiters. e.g: ifs do not require condition to be in parenthesis. I think enforcing that is easy, but then making it process statements in the same line would be pandora's box, specially since autohotkey doesn't have a non-expression statement separator.
vvhitevvizard wrote:
24 Jan 2019, 06:26
Well, w.o major overhaul of expressions parser, making an expected proper assume-mode for fat-arrow Func would fix the things. No need for local, static, etc keywords support inside expressions. Function (Func object's referenced body) should be assume-local by default, do u agree with me?
Download visual studio
Delete these two lines (may take a while to jump to it)
https://github.com/Lexikos/AutoHotkey_L/blob/alpha/source/script.cpp#L5710
Compile
Profit \o/
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: fat function in class method changes var outside itsscope

25 Jan 2019, 02:28

coffee wrote:
25 Jan 2019, 00:42
I'm not sure what you mean here. You don't need to use parenthesis to evaluate a variable inside an expression, or outside of one, barring that exception of object creation syntax and gosub/goto.
Similar syntax already exists for array declarations with variables enclosed in parenthesis:
Associative Arrays help wrote:Any expression can be used as a key, but to use a variable as a key, it must be enclosed in parentheses. For example, {(KeyVar): Value}
I would like the interpreter to be more strict and accept only such a way of using variables if they r meant to be used without any declaration/operations on them, e.g.:
( (ListVars), (Pause) ) , func1()=>(retval), func1()=>(x:=Round(4.6), (x)). this way AHK would know the user means these literals r variables and it is not a mistype.

In this and some other topics I struggle pushing idea of AHK having unified syntax. With sacrificing some backward compatibility ofc.
key1: "value1", ; looks similar to obj.key1 := "value1"
I see. Irregularity over irregularity. :) Well, mandatory quotes for key names would fix the ambiguity - that's actually what I do myself in my AHK scripts. And thats what required in JSON syntax - key names r always in quotes

2.
Btw, ternary ? and &&/|| (and/or) short-circuit operators used for expression body may be (according to tests) dramatically faster than IF-THEN commands - now, thx to ur explanation, I see
why. Essentially, it happens that recently I resort to if/then commands only when I need to use continue/break inside expressions. In most cases I'm ready to have the whole function body as 1 giant expression, e.g. (while cycle consisting of "parethesisized" expression blocks instead of regular curly brackets with commands):

Code: Select all

		while(++n<=n1)
			InStr(" `t`n`r",c:=SubStr(_s,n, 1),1) || ( ;1=CaseSensitive
				InStr(z,c,1) || E()
				, (c==q) ? (d:=InStr(_s,q,1, n+1),v:=SubStr(_s, n+1, d-n-1) ;str literals
					, n:=d, (!t) ? (k:=v, z:=':'):a ? (b.Push(v), z:=",]"):(b[k]:=v, z:=",}"))
				: (c==':') ? (t:=1, z:=x)
				: (c==',') ? (z:=(t:=a) ? x:q "{[")
				: InStr("}]",c,1) ? ((s.1=root) && E()
					, s.RemoveAt(1), y>>=1, b:=s.1, z:=(a:=y&1) ? ',]' : ',}')
				: InStr("{[",c,1) ? (s.Count()>o.Depth && E()
					, (c=='{') ? (t:=0, y:=y<<1&~1, z:=q '}') : (y:=y<<1|1, z:=x ']')
					, b.SetCapacity(256), s.InsertAt(1,v:={})
					, a ? b.Push(v):b[k]:=v, b:=s.1, a:=y&1)
				: (NumPut(&_s+n*2,fa), v:=SubStr(_s, n, d:=DllCall(fc)), n+=d-1 ;number
					, (v is "Number") ? v+=0:E(), a ? (b.Push(v), z:=",]"):(b[k]:=v, z:=",}"))
			)
its done this way b/c: 1) performance is required here 2) it lets me to inline/split sub-expressions the way I like 3) takes less screen space: the whole routine fits on 1 screen
I'm 99.99% positive every subexpression returns something
100.0% (if we dont count in exceptions). Sub-expression returns at least empty string "" or 0 (for boolean logic)
For commands yes, I don't like command "calling" either which is why I disabled that in my setup.
if removed completely, it would reduce resulting .exe file as well. Btw what other changes have u made for ur setup? Its getting interesting. :)
For other statements you can't do that since you have no mandatory delimiters. e.g: ifs do not require condition to be in parenthesis. I think enforcing that is easy, but then making it process statements in the same line would be pandora's box, specially since autohotkey doesn't have a non-expression statement separator.
Well, enforcing an expression to be enclosed in parenthesis obligatorily should fix it. e.g.: return(var), if(var==5), loop(var)
Delimiter between directives(commands) could be something similar to ; in C. This symbol is taken by commentary in AHK - but why not to change comments to # after all. okey, way too many radical changes even for alpha state. :D But again, having the syntax 100% C compatible would be a great achievement.

3.

Code: Select all

ab() {
	return (1,2,3,4,5) ; key point in the parenthesis here. That's what the fat arrow *is*. A function that returns a main expression that can have any number of subexpressions.
}
Yet fat arrow (Func type) as a whole is a bit more than just an expression w/o context (I return to the topic). lets pretend curly brackets, assume-xx commands and command in-lining r allowed in fat arrow's right expression:

Code: Select all

ab()=>{global, 1,2,3,4, return 5}
And assume-global scope is what gives me mixed feelings. We r not shortcutting a label placed outside function body with some expressions

Code: Select all

label:
  x:=1 ;x may be of global scope by default here - I couldn't care less. labels outside functions r just a bad programming style 
  (2,3,4)
  return 5
But with fat arrow (Func)) we r shortcutting a function body. With (expectedly) its own namespace scope. Yet global is made compulsive...

4.
Download visual studio
Delete these two lines (may take a while to jump to it)
https://github.com/Lexikos/AutoHotkey_L/blob/alpha/source/script.cpp#L5710

Code: Select all

if (!g->CurrentFunc->mOuterFunc)
		g->CurrentFunc->mDefaultVarType = VAR_DECLARE_GLOBAL;
thank u for the exact location of the culprit haha!!!

Tho I hate to download VS bloatware again. As I got it it requires latest VS. If it would be possible to compile it with GCC but alas from what I've seen the source is way too bound to Microsoft's compiler all over the place. I need to find a way... maybe there r some online Visual C++ compilers.
like this one (it lets u set compiler args) https://rextester.com/l/cpp_online_compiler_visual but for the whole projects.
This one seems to be serious (havent tested) but its trial mode is time-limited https://turbo.net/run/microsoft/vccompiler
Last edited by vvhitevvizard on 25 Jan 2019, 09:08, edited 1 time in total.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: fat function in class method changes var outside itsscope

23 Apr 2019, 06:56

it seems base, this not yet defined at static evaluation time for prototype classes
this is merely a parameter of a method, supplied a value when the method is called. The value is supplied either implicitly (from target in target.method()), or as an explicit parameter when the method's implemention function is called directly or via .Call(). Static initializers may be contained within a method, but are evaluated on startup. The function is not called, so the parameter is not supplied a value. Static initializers for class variables have no method in the first place, so no this. You can refer to a global variable by that name if you wish...

base, on the other hand, is never defined. "base only has special meaning if followed by a dot . or brackets []". When it is used that way, and only then, the base class is invoked by retrieving the base of the class which contains the current function's definition (known at load time), but passing the value of the current function's first parameter as this. Even inside a method, x := base will get nothing, unless you assigned a value to base, in which case base.method() will call that value, not necessarily your base class.

After working on Object.ahk, I imagined replacing this usage of base with super, a new (to AutoHotkey, but not the world) keyword which would perhaps not be valid in any other context.

I cant find a way to use [A_ThisFunc] to call the current method at load time.
A_ThisFunc contains the name of the currently executing function. Static initializers are either contained by a function which is not executing at the time the initializer is evaluated, or not even contained by a function.

Of course A_ThisFunc.Call() will not work by default; A_ThisFunc returns a string, and strings have no Call method. As Helgef wrote, you shouldn't try random stuff. Technically, you could add a Call method for strings. %A_ThisFunc%.Call() could work if the current function's name is also a variable name, and that variable contained a callable object.



I can see some value in this within a static initializer referring to the class. This could be achieved by lumping the static initializers together into one implicit method, and calling that method at startup. This is how non-static initializers in the class body work. It would mean that all static class variables would be initialized together, and could not be interspersed with the static initializers that exist inside methods (i.e. they would no longer strictly be executed in the order they are defined in the script).

I can see some value in A_ThisFunc being available to static initializers. In that case it is not the name of the current function, but the function whose body contains the static initializer; a function which has not yet been called. It would be trivial to replace the reference to A_ThisFunc with a string at load time. However, the cause of the problem with A_ThisFunc is that static initializers execute outside the context of the function. This causes other problems as well.

In other contexts, having A_ThisFunc resolved at runtime increases flexibility. For instance, A_ThisFunc can be used to determine which function called a global label (which could be a hotkey or hotstring label). (In v1, it can also be used to determine whether a label inside a function was called externally by something like SetTimer, Menu or a hotkey. However, v2 has local labels, which cannot be called externally.)

I am certain that the use of both this and A_ThisFunc in static initializers has been discussed before, probably multiple times.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: fat function in class method changes var outside itsscope

24 Apr 2019, 22:06

vvhitevvizard wrote:
20 Jan 2019, 21:39
btw, I understand obj.key returns string not an address, but why dont we have unified syntax here allowing to get address of obj's property with & operator: &obj.key the same way it works with variables?
The expression var does not return a value, but a variable reference. It is not dereferenced until another operator is applied to it, or it is passed to a function, or it becomes the result of the overall expression. For instance, the expression (c ? a : b) can be passed ByRef or used as the target of an assignment.

By contrast, obj.key is evaluated like the pseudo-code ObjGet(obj, "key") (which in early versions, was real code). & would be applied to the value returned by the property. In v2, &obj.key is valid because &(any string expression) is valid, but it operates on a temporary copy of the string, not the object's field.

In fact, the object might not have any fields. obj.key might call a property-getter or meta-function, and might have no storage location at all. If overloaded operators are ever made possible, it is likely that &obj.key would be transformed to something like obj.GetAddress("key") or obj.__addr("key"), while &(obj.key) would still operate on the value returned by obj.key.

(There's also the possibility that obj.key returns an object, and & retrieves the object's address.)

nnnik wrote:
21 Jan 2019, 02:42
Every line that contains the prefix static is executed in global scope ...
This could be misleading with respect to static initializers inside functions. "Scope" is usually used in reference to how names are resolved, but most names are resolved at load time, in local scope. Static initializers can refer to other static variables, and those exist only in local scope. I think it's better to say that static initializers are executed in global context, and as a result, dynamic references use global scope.
... before the script fully starts.
That's true only by definition. If the script is executing a static initializer, some static variables haven't been initialized yet, so you could say the script hasn't "fully started". Where do you draw the line? Maybe the script does initialization in the auto-execute section, in which case it hasn't "fully started" until the auto-execute section finishes. But maybe the auto-execute section never finishes. In that case, has the script "fully started" only when the program finally exits?

I prefer to think that the "start" is when script code begins to execute. In that case, static initializers are executed at the very "start", before anything else (except other functions that are called by static initializers). You can instead say that static initializers are executed before the auto-execute section.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: fat function in class method changes var outside itsscope

25 Apr 2019, 05:41

This could be misleading with respect to static initializers inside functions. "Scope" is usually used in reference to how names are resolved, but most names are resolved at load time, in local scope. Static initializers can refer to other static variables, and those exist only in local scope. I think it's better to say that static initializers are executed in global context, and as a result, dynamic references use global scope.
Thats good info 👍
That's true only by definition. If the script is executing a static initializer, some static variables haven't been initialized yet, so you could say the script hasn't "fully started". Where do you draw the line? Maybe the script does initialization in the auto-execute section, in which case it hasn't "fully started" until the auto-execute section finishes. But maybe the auto-execute section never finishes. In that case, has the script "fully started" only when the program finally exits?

I prefer to think that the "start" is when script code begins to execute. In that case, static initializers are executed at the very "start", before anything else (except other functions that are called by static initializers). You can instead say that static initializers are executed before the auto-execute section.
Yeah but what is script code?
To me a script is a unity of multiple connected components that offer functionality.
To me the first line that moves towards and is aware of this instance of unity marks the start of the script.
E.g. if I have a script that includes GDIP then:

Code: Select all

#include gdip.ahk

pToken := Gdip_startup() ;script starts here
GUi,XYZ:New
The line pToken := Gdip_startup()marks the start of the script because it contains information unique to this script.
It states that GDIp should be loaded right from the start and available from that point.
Despite the fact that Gdip normally is started up at that point in 99% of all scripts using it the line isn't redundant.
However if a line was in fact redundant with the include above it it would be part of the include/part of the imported component and the script code starts below it.
I usually initialize my components using static initializers. Since I don't want to cause any issues with uninitialized components I usually start the script in the autoexecute section.

This is slightly offtopic though since at the time I just broke down a complex context into simple terms.
Recommends AHK Studio
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: fat function in class method changes var outside itsscope

26 Apr 2019, 00:35

:facepalm:

All code written in the AutoHotkey language is script code.

But not all script code gets executed.

Return to “AutoHotkey Development”

Who is online

Users browsing this forum: No registered users and 35 guests