AHK v2: converting/optimizing scripts Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

AHK v2: converting/optimizing scripts

06 Dec 2018, 14:27

We discuss multiple AHK v2 issues here. Converting from AHK v1.1, optiming for performance and code size.
Chime in!

page 1: using %% operator to deref "obj1.objN.key" stringified objects
page ~5: super-optimized json in-out function.
page 8: pretty-printing of stringified Float numbers. alternative to Format
page ~10: improving mcode
page 13: fastest StrLen for not AHK-returned strings

//////////////////////////////

Deref issue

1)

Code: Select all

class a1{
	static Key1:="some string"
	static Key2:="another string"
}

for i,k in ["a1.Key1", "a1.Key2"]{ ;array with prototype class members
	%k%:="new value" 
}
So the idea is I have a list of "object.value" (prototype class name in this case) and would like to dynamically deref in order to change those vars' content.
but the above code gives an AHK error: "the following var name contains an illegal character". deref doesn't work with .names

2)

Code: Select all

for i,k in [a1.Key1, a1.Key2]{ ;array with prototype class members
	k:="new value"
}
	msgbox(a1.Key1 "|" a1.Key2)
doesn't work as well: I can read values but can't write

3)

Code: Select all

class a1{
	static Key1:="some string"
	static Key2:="another string"
}

for i,k in ["a1.Key1", "a1.Key2"]{ ;array with prototype class members
	m:=StrSplit(k,"."), %m[1]%[m[2]]:="new value"
}
	msgbox(a1.Key1 "|" a1.Key2)
the code above works
Is there a simpler way to achieve the purpose?

btw, a line from the code above:

Code: Select all

m:=StrSplit(k,"."), u:=%m[1]%[m[2]], u:="new value"
doesn't work as well; I can read values but can't write
So I have to use:

Code: Select all

m:=StrSplit(k,"."), u:=%m[1]%,p:=m[2], u[p]:="new value"
Last edited by vvhitevvizard on 25 Dec 2018, 11:08, edited 7 times in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: a few bugs

06 Dec 2018, 14:49

Those are not bugs at all.
I will move the post to the Ask for help forums.
Recommends AHK Studio
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: a few bugs

06 Dec 2018, 14:57

nnnik wrote:
06 Dec 2018, 14:49
Those are not bugs at all.
I will move the post to the Ask for help forums.
I see. But is there a way to get rid of %deref% syntax and use something like (I know *(pointer operator) was removed in AHK v2):

Code: Select all

for i,k in [a1.Key1, a1.Key2] ;array with prototype class members
	*k:="new value"

Once again, the code is related to AHK v2. And I have a feeling that %deref% operator might be removed completely in the future. So please help me out of achieving the task with something like:
1) get a pointer (or &address) to a dynamic or prototype object by its "string name";
2) change resulting object["property"]'s content
Last edited by vvhitevvizard on 09 Dec 2018, 17:03, edited 2 times in total.
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

06 Dec 2018, 18:31

Hi, something like this has worked for me in the past:

Code: Select all

class a1 {
	static Key1:= "some string"
	static Key2:= "another string"
}

for _, k in ["a1.Key1", "a1.Key2"] { ;array with prototype class members
	parts := StrSplit(k, ".")
	objname := parts[1]
	parts.RemoveAt(1)
	%objname%[parts*] := "new value for " k 
}

msgbox(a1.Key1)
msgbox(a1.Key2)
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

06 Dec 2018, 18:45

thx for ur feedback. yeah, ur weird code does work in AHK v2
but it makes things even more complicated. and we still use %deref% here.
and tbh I don't get what is parts* - haven't they removed *(pointer operator) long time ago? :D

PS: What I meant is need for some kind of built-in function to convert strings "object.property" like ObjBindMethod() does for strings "method name". Tho the latter doesn't accept "string name" as an object:
4)

Code: Select all

for i,k in ["a1.Key1", "a1.Key2"]
    m:=StrSplit(k,"."), u:=ObjBindMethod(m[1],m[2]), u:="new string"
ObjBindMethod() says "parameter #1 is invalid" :D
Last edited by vvhitevvizard on 09 Dec 2018, 17:05, edited 5 times in total.
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

06 Dec 2018, 18:48

Oh, it's there so something like this would work:

Code: Select all

class a1 {
	static Key1:= "some string"
	static Key2:= "another string"
	class test {
		static Key3 := "more string"
	}
}

for _, k in ["a1.Key1", "a1.Key2", "a1.test.Key3"] { ;array with prototype class members
	parts := StrSplit(k, ".")
	objname := parts[1]
	parts.RemoveAt(1)
	%objname%[parts*] := "new value for " k 
}

msgbox(a1.Key1)
msgbox(a1.Key2)
msgbox(a1.test.Key3)
You can wrap it in a function, too if you use it a lot.
Also, I don't think it's going away, since it's quite powerful!

As for your other questions, I have no idea! Perhaps someone else can chime in.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

06 Dec 2018, 19:12

oif2003, now I see parts* as a "variadic-dimensional" array, stupid me @ 3am =) A very handy cycle for dereffing nested objects! and it does work in v2.

But %objname% deref is still there. It was my afterthought 2nd question in the topic; do u have any ideas how to do it w/o deref?
There r quite alot examples where operators/built-in functions accept "strings" as objects/keys: object["name"], func("name"). Why can't we have the same for objects? Or do we?
Last edited by vvhitevvizard on 09 Dec 2018, 17:05, edited 1 time in total.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

06 Dec 2018, 19:33

oif2003 wrote:
06 Dec 2018, 18:48
You can wrap it in a function, too if you use it a lot.
Here is the wrapped function as u suggested. :D Here we go into another trouble: when Name2Addr() returns the reference, that's not the original value's address:

Code: Select all

class a1 {
	static Key1:= "some string"
	static Key2:= "another string"
	class test {
		static Key3 := "more string"
	}
}


Name2Addr(_s){ ;_s: string "obj1.objN.key"
	m:=StrSplit(_s,"."), o:=m[1], m.RemoveAt(1), u:=%o%[m*]
	msgbox(u) ; "some string", "another string", "more string"
	return u
}

for _,k in ["a1.Key1", "a1.Key2", "a1.test.Key3"] ;array with prototype class members
	u:=Name2Addr(k), u:="new " k

msgbox(u) ; "new a1.test.Key3"
msgbox(a1.Key1 "|" a1.Key2 "|" a1.test.Key3) ; "some string|another string|more string"
Last edited by vvhitevvizard on 09 Dec 2018, 17:06, edited 2 times in total.
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

06 Dec 2018, 20:08

I was playing with this and it seems to work. Maybe we can shorten it a little?

Code: Select all

class a1 {
	class test {
		static Key3 := "more string"
	}
}

class obj {
	str[s] {
		get {
			return (m := StrSplit(s, "."), o := m[1], m.RemoveAt(1), %o%[m*])
		}
		set {
			m := StrSplit(s, "."), o := m[1], m.RemoveAt(1), %o%[m*] := value
		}
	}
}

obj.str["a1.test.key3"] := "A test"
msgbox a1.test.key3
msgbox obj.str["a1.test.key3"]
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

06 Dec 2018, 20:28

just wow! U've come back with a really handy one
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

06 Dec 2018, 20:39

Thanks! Now we wait for someone else to answer your other questions.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Problems with objects and legacy syntax

07 Dec 2018, 06:12

If you use one root object to store all the data you could access it all with the variadic parameter syntax.
Recommends AHK Studio
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

07 Dec 2018, 12:07

nnnik wrote:
07 Dec 2018, 06:12
If you use one root object to store all the data you could access it all with the variadic parameter syntax.
Good solution as well! We get rid of outdated %deref% syntax this way! It would be possible to wrap up all class prototypes and other globals, but that increases code size.

Is it possible for the case to utilize "" root object in reference evaluating expressions, something like:

Code: Select all

reference:="".base["a1.Key1"]
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

11 Dec 2018, 12:03

oif2003 wrote:
06 Dec 2018, 20:08
Maybe we can shorten it a little?
I optimized it a bit. Removed intermediate var o and made the whole calculation as a single operation:

Code: Select all

class obj{
	str[_s]{ ;deref string
		get{ ;v:=["obj1.objN.key"]
			return(%(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]) ;[m*] =variadic multi-dimentional
		}
		set{ ;["obj1.objN.key"]:=v
			%(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]:=value
		}
	}
}
btw, is it possible to use fat arrow syntax () => (like in the example below) with property definitions?

Code: Select all

obj.setWidth(10)
MsgBox(obj.getWidth())

class obj{
  static w:=55
  static setWidth:=(this, value) =>this.w:=value
  static getWidth:=(this) =>this.w
}
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

11 Dec 2018, 12:32

Nice! You've made it 10% faster according to my not very sophisticated benchmark.

Do you mean something like this? What is it for if you don't mind me asking? So I can understand it better.

Code: Select all

class obj{
	str[_s]{ 
		get { 
			return(%(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]) 
		}
		set { 
			%(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]:=value
		}
	}
}

ostr(p*) => p.length() > 1 ? obj.str[p[1]] := p[2] : obj.str[p[1]]
 
ostr("a1.test.key3", 10000)
msgbox(ostr("a1.test.key3"))
Just out of curiosity, I compared

Code: Select all

ostr1(p*) => p.length() > 1 && (%(m:=StrSplit(p[1],".")).RemoveAt(1)%[m*]:=p[2]) || %(m:=StrSplit(p[1],".")).RemoveAt(1)%[m*]
ostr2(p*) => p.length() > 1 ?  (%(m:=StrSplit(p[1],".")).RemoveAt(1)%[m*]:=p[2]) :  %(m:=StrSplit(p[1],".")).RemoveAt(1)%[m*]
ostr3(p*) => p.length() > 1 ?  obj.str[p[1]] := p[2]							 :  obj.str[p[1]] 
The first two are about the same in speed while the last one is about 30% slower. Set/Get is still faster.
Last edited by oif2003 on 11 Dec 2018, 12:52, edited 1 time in total.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

11 Dec 2018, 12:52

oif2003 wrote:
11 Dec 2018, 12:32
Do you mean something like this?
Not for this use case, :D I meant fat arrows used for property's half-methods declarations. the following code is not working ("Unknown property" error), just to give u an idea.

Code: Select all

class a1{
	static key1:="string1"
}

deref["aa.key1"]:="new"

class deref{
	static set:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]:=value
	static get:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]
}
and the next gives an error "Not a valid property getter/setter":

Code: Select all

class a1{
	static key1:="string1"
}

obj.deref["aa.key1"]:="new"

class obj{
	deref[_s]{
		set:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]:=value, get:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]
	}
}
I'm fumbling the proper syntax if there r any. :D The target is to "inline" property's get/set declarations
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

11 Dec 2018, 13:07

Oh, I see. I really like how you wrote deref class there. It saves typing awkward things like obj.str (gets rid of the dot). I actually wanted to do something similar like that in the past, but couldn't figure out how to do it.

Edit: Missed this when I first tested it, but deref["a1.key1"] returns "new" while a1.key1 remains as "string1". Back to normal set/get for now, I guess.

Code: Select all

class a1{
	static key1:="string1"
}

deref["a1.key1"]:="new"

msgbox(deref["a1.key1"])
msgbox(a1.key1)

class deref{
	static set:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]:=value
	static get:=(_s) => %(m:=StrSplit(_s,".")).RemoveAt(1)%[m*]
}
But then wouldn't your second example (even if it worked) be equivalent to normal get{....}, set{....}?
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

11 Dec 2018, 13:23

vvhitevvizard wrote:
11 Dec 2018, 12:52
I'm fumbling the proper syntax if there r any. :D The target is to "inline" property's get/set declarations
I attempted that before without luck. Can't even drop the { } after putting everything on a single line:

Code: Select all

get
	...
didn't work, so I eventually gave up.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Problems with objects and legacy syntax

11 Dec 2018, 13:48

oif2003 wrote:
11 Dec 2018, 12:32
The first two are about the same in speed while the last one is about 30% slower. Set/Get is still faster.
U mean the last one is 30% as fast? :D Good to know! :thumbup:

edited: code removed - see next page for the correct one
Last edited by vvhitevvizard on 11 Dec 2018, 15:15, edited 3 times in total.
oif2003
Posts: 214
Joined: 17 Oct 2018, 11:43
Contact:

Re: Problems with objects and legacy syntax

11 Dec 2018, 14:06

Hey, this is what I end up with for the moment. I really hate that extra dot!

Code: Select all

class a {
	class test {
		static key := 0
	}
}

class _deref {
	__New() {
		static initialize := new _deref()
		global deref := this
	}	
	__Set(s, value) {
		return %(m := StrSplit(s, ".")).RemoveAt(1)%[m*] := value
	}
	__Get(s) {
		return %(m := StrSplit(s, ".")).RemoveAt(1)%[m*] 
	}
}

t := A_TickCount
loop 1000000 {
	deref["a.test.key"]++
}
msgbox(A_TickCount - t " : " a.test.key)

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: gdzrh917 and 32 guests