Allow .Property / .Method() syntax within methods/functions

Discuss the future of the AutoHotkey language
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Allow .Property / .Method() syntax within methods/functions

05 Jul 2014, 22:57

Currently:

Code: Select all

class Test
{
	method() {
		this.property := "some value" ;// set
		this.another_method() ;// call
	}
}
;// OR
function(obj) {
	obj.property := "some value"
	obj.another_method()
}
My Proposal:

Code: Select all

class Test
{
	method() {
		.property := "some value" ;// set
		.another_method() ;// call
	}
}
;// AND / OR
function(obj) {
	.property := "some value"
	.another_method()
}
By omitting the variable that refers to an object, the property or method specified will invoke the object that called the method or function.

PROS:
  • Ensures that the call always invokes the invoked object even if the variable that refers to that object (in most cases this) is assigned a different value. Kinda similar to the usage/purpose of the LastFoundWindow.
  • Shorter and IMHO more understandable -> OK, this line is invoking the object that called this method(no need to look-up the value of this or whatever variable).
CONS:
  • Could be unfriendly to the eyes
  • Might not be readable to others
  • Error prone?? Delete the dot and it does something totally different.
lexikos
Posts: 6657
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 00:47

This conflicts with the continuation syntax. Lines beginning with any expression operator, including dot, are automatically appended to the previous line.
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 03:22

Oops, I totally forgot about that... If this suggestion is reasonable, will using a new operator help? Say, @property := "some value", @another_method() OR ->property := "some value", ->another_method(). Form a language perspective, is this proposal reasonable?
HotKeyIt
Posts: 1886
Joined: 29 Sep 2013, 18:35
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 04:33

I assume you are referring to With.. End With Vba syntax.
Actually it is already possible to make something similar in ahk.
Normally we would write:

Code: Select all

o:={Alex:{details:[]}},          SetUser(o,"Alex","active",A_Now)
MsgBox % o.alex.details.status

SetUser(this,u,s,l){
  this[u].details.Name:=u
  ,this[u].details.Status:=s
  ,this[u].details.LastActive:=l
}
Here we use the for loop to assign our object to a temporary variable and we can access it directly.
It is not perfect but saves a lot of typing and can be a lot faster because we don't need to resolve the objects in each expression.

Code: Select all

o:={Alex:{details:[]}},                SetUser(o,"Alex","active",A_Now)
MsgBox % o.alex.details.status

SetUser(this,u,s,l){
  for Each,_ in [ this[u].details ]
    _.Name:=u  ,_.Status:=s  ,_.LastActive:=l
}
User avatar
fincs
Posts: 504
Joined: 30 Sep 2013, 14:17
GitHub: fincs
Location: Seville, Spain
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 05:43

I like the @field/@method() idea (which is preparsed into this.field and this.method() respectively). In fact, I think it should suffice to edit the expression parser to replace the @ token by this (SYM_VAR) followed by . (SYM_DOT, *not* SYM_CONCAT).
fincs
Windows 10 x64 Build 18362 | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v1.1.31.01
Get SciTE4AutoHotkey v3.0.06.01 - [My project list]
User avatar
RobertL
Posts: 540
Joined: 18 Jan 2014, 01:14
Location: China

Another way?

06 Jul 2014, 06:14

HotKeyIt wrote:Here we use the for loop to assign our object to a temporary variable and we can access it directly.

Code: Select all

SetUser(this,u,s,l){
  for Each,_ in [ this[u].details ]
    _.Name:=u  ,_.Status:=s  ,_.LastActive:=l
}
I'm not sure if there's some skills. Why not use this ?

Code: Select all

SetUser(this,u,s,l){
    _:=this[u].details
    _.Name:=u  ,_.Status:=s  ,_.LastActive:=l
}
;Or
SetUser(this,u,s,l){
    this.Name:=u  ,this.Status:=s  ,this.LastActive:=l
}
SetUser(o.[u].details,...)
Replyed below 1 by HotKeyIt, 2 by lexikos.

Also, see my post below.
Last edited by RobertL on 06 Jul 2014, 23:16, edited 6 times in total.
我为人人,人人为己?
User avatar
fincs
Posts: 504
Joined: 30 Sep 2013, 14:17
GitHub: fincs
Location: Seville, Spain
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 07:39

Figured out a way to implement @field and @method():

Code: Select all

------------------------------ source/script.cpp ------------------------------
index 3c0813f..572496f 100644
@@ -4110,6 +4110,7 @@ ResultType Script::ParseAndAddLine(LPTSTR aLineText, ActionTypeType aActionType
 			if (end_marker && (*end_marker == '(' || *end_marker == '[') // v1.0.46.11: Recognize as multi-statements that start with a function, like "fn(), x:=4".  v1.0.47.03: Removed the following check to allow a close-brace to be followed by a comma-less function-call: strchr(action_args, g_delimiter).
 				|| *action_args == g_DerefChar // Something beginning with a double-deref (which may contain expressions).
 				|| *aLineText == '(' // Probably an expression with parentheses to control order of evaluation. In this case, aLineText == action_args, so it was already handled by the condition above.
+				|| *aLineText == '@' // Shorthand class member access.
 				)
 			{
 				aActionType = ACT_EXPRESSION; // Mark this line as a stand-alone expression.
@@ -5683,6 +5684,7 @@ ResultType Script::ParseOperands(LPTSTR aArgText, LPTSTR aArgMap, DerefType *aDe
 			switch (*op_begin)
 			{
 			case '.':
+			case '@':
 				// This case also handles the dot in `.=` (the `=` is skipped by the next iteration).
 				// Skip the numeric literal or identifier to the right of this, if there is one.
 				// This won't skip the signed exponent of a scientific-notation literal, but that should
@@ -9060,9 +9062,30 @@ ResultType Line::ExpressionToPostfix(ArgStruct &aArg)
 					break;
 
 				default: // NUMERIC-LITERAL, DOUBLE-DEREF, RELATIONAL OPERATOR SUCH AS "NOT", OR UNRECOGNIZED SYMBOL.
-					if (*cp == '.') // This one must be done here rather than as a "case".  See comment below.
+					if (*cp == '.' || *cp == '@') // This one must be done here rather than as a "case".  See comment below.
 					{
-						if (cp1 == '=')
+						if (*cp == '@')
+						{
+							// Class member access (translated to "this.")
+							if (IS_SPACE_OR_TAB(cp[-1]))
+							{
+								CHECK_AUTO_CONCAT;
+							}
+							// Ensure we are inside a class method
+							Func* func = g->CurrentFunc;
+							if (!func)
+								return LineError(ERR_BAD_MEMBER_ACCESS, FAIL, cp);
+							if (!func->mClass)
+								return LineError(ERR_BAD_MEMBER_ACCESS, FAIL, cp);
+							// Ensure at least enough room for inserting the 'this' variable reference.
+							if (infix_count > MAX_TOKENS - 2)
+								return LineError(ERR_EXPR_TOO_LONG);
+							infix[infix_count].symbol = SYM_VAR;
+							infix[infix_count].var = func->mParam[0].var; //g_script.FindOrAddVar(_T("this"));
+							infix_count++;
+							// Proceed as usual.
+						}
+						else if (cp1 == '=')
 						{
 							++cp; // An additional increment to have loop skip over the operator's second symbol.
 							this_infix_item.symbol = SYM_ASSIGN_CONCAT;

------------------------------- source/script.h -------------------------------
index f9cd4f0..b7ba0c7 100644
@@ -165,6 +165,7 @@ enum CommandIDs {CONTROL_ID_FIRST = IDCANCEL + 1
 #define ERR_UNEXPECTED_CLOSE_PAREN _T("Unexpected \")\"")
 #define ERR_UNEXPECTED_CLOSE_BRACKET _T("Unexpected \"]\"")
 #define ERR_UNEXPECTED_CLOSE_BRACE _T("Unexpected \"}\"")
+#define ERR_BAD_MEMBER_ACCESS _T("Class member access outside of class method.")
 #define ERR_UNEXPECTED_COMMA _T("Unexpected comma")
 #define ERR_BAD_AUTO_CONCAT _T("Missing space or operator before this.")
 #define ERR_MISSING_CLOSE_QUOTE _T("Missing close-quote") // No period after short phrases.
@@ -866,10 +867,10 @@ public:
 	// e.g. WinMove, -%x%, -%y%:
 	#define EXPR_TELLTALES EXPR_COMMON _T("\"")
 	// Characters that mark the end of an operand inside an expression.  Double-quote must not be included:
-	#define EXPR_OPERAND_TERMINATORS_EX_DOT EXPR_COMMON _T("%+-?\n") // L31: Used in a few places where '.' needs special treatment.
+	#define EXPR_OPERAND_TERMINATORS_EX_DOT EXPR_COMMON _T("%[email protected]\n") // L31: Used in a few places where '.' needs special treatment.
 	#define EXPR_OPERAND_TERMINATORS EXPR_OPERAND_TERMINATORS_EX_DOT _T(".") // L31: Used in expressions where '.' is always an operator.
 	#define EXPR_ALL_SYMBOLS EXPR_OPERAND_TERMINATORS _T("\"'")
-	#define EXPR_ILLEGAL_CHARS _T("\\;`@#$") // Characters illegal in an expression.
+	#define EXPR_ILLEGAL_CHARS _T("\\;`#$") // Characters illegal in an expression.
 	// The following HOTSTRING option recognizer is kept somewhat forgiving/non-specific for backward compatibility
 	// (e.g. scripts may have some invalid hotstring options, which are simply ignored).  This definition is here
 	// because it's related to continuation line symbols. Also, avoid ever adding "&" to hotstring options because
It could easily be expanded to also support using the first parameter of non-class functions, however IMO that behaviour would be too obscure.
fincs
Windows 10 x64 Build 18362 | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v1.1.31.01
Get SciTE4AutoHotkey v3.0.06.01 - [My project list]
HotKeyIt
Posts: 1886
Joined: 29 Sep 2013, 18:35
Contact:

Re: Another way?

06 Jul 2014, 13:09

RobertL wrote:Why not use this ?

Code: Select all

SetUser(this,u,s,l){
    _:=this[u].details
    _.Name:=u  ,_.Status:=s  ,_.LastActive:=l
}
This is just to save a variable, since for loop uses its 'own' variables. The function is surely not best example but in complex script it avoids conflict with other variables.
User avatar
fincs
Posts: 504
Joined: 30 Sep 2013, 14:17
GitHub: fincs
Location: Seville, Spain
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 13:33

I suppose that a with var := value block could be added that uses the same "privatisation" technique that v2 for loops use, e.g.:

Code: Select all

with temp := someObj.deepIntoTheDom[1,2].content
{
    msgbox % temp.someProp " - " temp.anotherProp
    temp.someMethod(1,2)
}
However I highly doubt its usefulness.
fincs
Windows 10 x64 Build 18362 | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v1.1.31.01
Get SciTE4AutoHotkey v3.0.06.01 - [My project list]
just me
Posts: 6551
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 15:22

Code: Select all

class Test
{
   method() {
      .property := "some value" ;// set
      .another_method() ;// call
   }
}
This would save 4 letters. Am I missing any other advantage?

If at all, I would vote for a With command, because it might save more letters (but also without further advantages). :roll:
User avatar
joedf
Posts: 7339
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 15:45

Code: Select all

func(@obj, param, etc) { ;select 'Obj' for shorthand?
    Var := "foo"
    @method()
    @propertyA := Var
    @propertyB := "bar"
}
I find it better with the "selector" option :P
Edit: or maybe..??

Code: Select all

obj := {test: 1, bob: 23}
Obj @= { jack: 56, apple: 67} ;"append" properties ?!
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 4.00 GHz, 2x8GB G.Skill RipJaws V - DDR4 3280 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
HotKeyIt
Posts: 1886
Joined: 29 Sep 2013, 18:35
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 16:01

fincs wrote:I suppose that a with var := value block could be added that uses the same "privatisation" technique that v2 for loops use.
I think that would be useful especially using multiple variables, the code is clearer and will surely reduce errors in complex scripts:

Code: Select all

with this := someObj.deep[1,2].content,that := otherObj.deep[1,2].content
{
    msgbox % this.someProp " - " that.someMethod(1,2)
}
guest3456
Posts: 2773
Joined: 09 Oct 2013, 10:31

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 18:22

that @ syntax is disgusting

User avatar
joedf
Posts: 7339
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada
Contact:

Re: Allow .Property / .Method() syntax within methods/functi

06 Jul 2014, 19:50

How about * ?
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 4.00 GHz, 2x8GB G.Skill RipJaws V - DDR4 3280 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
lexikos
Posts: 6657
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Another way?

06 Jul 2014, 22:38

* looks too much like C style deref, which is also what *x currently does.

I don't think we need any new/unconventional syntax for this. The "problem" can easily be solved with a simple hotkey @::Send this. or regex hotstring for @\w+.
HotKeyIt wrote:This is just to save a variable, since for loop uses its 'own' variables.
It doesn't save anything. It is longer to type and less efficient than simply assigning and clearing a variable. If your function is so large/complex that you risk a variable conflict, you should be refactoring it.
User avatar
RobertL
Posts: 540
Joined: 18 Jan 2014, 01:14
Location: China

Another way to define and use relative reference

06 Jul 2014, 22:59

lexikos wrote:This conflicts with the continuation syntax. Lines beginning with any expression operator, including dot, are automatically appended to the previous line.
Can add syntax, lines beginning with dot, previous line ending with comma (or any others like.. which CANT be appended to), preparse dot to this (or specified Base).
Means use previous result of a var as base / relative reference, like an dynamic kind of Assume-local/global/static about var define within function in V2.
So we coulud use.

Code: Select all

method(){
	;This this.a()/this.b/this.c
	.a(),	;Default of base is "this"
	.b="b",	;Started with dot, but cant append to previous line for there is a comma.
	c:=.c	;Not started with dot
	
	That	;Change base.
	.A(),
	.B="B",
	C:=.C
	;Equals
	;	That
	;	.A(),.B="B",C:=.C
	;Even these
	A.B.C
	.D1,	;A.B.C.D1
	.D2,	;A.B.C.D2

	;Or this syntax
	a..	;Double dot ending to define base?
	.b,	;a.b
	.c	;a.c
}
It's just an obscure view~


Currently in v2

Code: Select all

o:={}
.a:=1,	;not skipped, but append to the front line.
.b:=2	;has no effects (because of the comma above), without warn nor error.
我为人人,人人为己?

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 9 guests