[V2] trick to read Map values as properties

Put simple Tips and Tricks that are not entire Tutorials in this forum
AHK_user
Posts: 523
Joined: 04 Dec 2015, 14:52
Location: Belgium

[V2] trick to read Map values as properties

08 Jul 2022, 13:39

This hack can be used to be able to read the values of a map object as a property, if somebody prefers this syntax.
I learned this trick from thqby. :D :D :D

Funny fact, if you forget to set the CaseSense to Off, the "property" syntax becomes casesensitive. :crazy:

Code: Select all

#Requires AutoHotkey v2.0-beta
#SingleInstance force
oMap := Map()
oMap.CaseSense := "Off"
oMap.Set("Red", "ff0000", "Green", "00ff00", "Deep Blue", "0000ff")

oMap.DefineProp('__get', { call: oMap.Get }) ; Trick of thqby

MsgBox('oMap["Red"]:' oMap["Red"] "`noMap.Red:" oMap.red)
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: [V2] trick to read Map values as properties

09 Jul 2022, 13:50

I prefer the object-oriented syntax

Code: Select all

#Requires AutoHotkey v2.0-beta
#SingleInstance force
oMap := Map()
oMap.CaseSense := "Off"
oMap.Set("Red", "ff0000", "Green", "00ff00", "Deep Blue", "0000ff")

oMap.__get := (this, p*) => this.get(p*) ; Trick of thqby

MsgBox('oMap["Red"]:`t' oMap["Red"] "`noMap.Red:`t" oMap.red)
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: [V2] trick to read Map values as properties

09 Jul 2022, 23:20

I prefer the object-oriented syntax
1) There's nothing more or less "object-oriented" about the syntax.
2) This isn't just a matter of syntax.

oMap.__get := ... creates a value property which can be overwritten by assigning __get again.
oMap.DefineProp('__get', { call: ... }) defines a method which cannot be overwritten by assignment.

oMap.Get is a built-in function which takes two parameters: Key, Default.
(this, p*) => this.get(p*) is a user-defined function which takes a variable number of parameters and just calls the built-in method. It is useless overhead (in this example).

If the meta-function was defined for Map.Prototype or in a Map subclass and it called this.get(p*), it would potentially call a Get method defined by a subclass of that class. That could be a benefit.

None of the implementations above are correct, because the usage of __Get and Get do not match. oMap.Blue will return an empty Array. oMap.Blue[1] will return an array of parameters; i.e. [1], which coincidentally looks the same as the indexer syntax.

Meta-functions have a fixed number of parameters, with the second parameter being the [parameters*] (an Array), which is always passed. The point is that the meta-function is required to handle the parameters, otherwise they would be ignored. Obviously, it's possible to circumvent that requirement by incorrectly using the variadic syntax.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: [V2] trick to read Map values as properties

10 Jul 2022, 09:25

Okay, I see how the __Get() function signature doesn't map that of get()

This is what I've come up with:

Code: Select all

oMap.DefineProp('__get', { call: (this, prop, *) => oMap.Get(prop, "") }) ; Trick of thqby
oMap.__get := (this, prop, *) => this.get(prop, "")                                 ; iseahound
I don't see how to remove the fat arrow syntax, perhaps implied by your above comment (or did I read it wrong? and that oMap.__get := oMap.get would suffice for the simple version)
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: [V2] trick to read Map values as properties

10 Jul 2022, 19:40

I didn't suggest removing the fat arrow function. To adapt the different expectations of the two methods (which hadn't been done "(in this example)"), you need an intermediary function.

This new version makes oMap.prop less robust than oMap["prop"]; it defaults to "" instead of throwing the appropriate error.

If you omit the second parameter of Get, you must make an exception for the Default property, or define it, to prevent infinite recursion. An alternative to omitting the second parameter would be to pass a unique default value and throw PropertyError if that value is returned.

The new version also still fails to handle cases where [parameters] are specified after the property, and will cause them to be ignored, as I explained.

It also references the wrong variable; oMap.Get should be this.Get.
iseahound
Posts: 1582
Joined: 13 Aug 2016, 21:04
Contact:

Re: [V2] trick to read Map values as properties

14 Jul 2022, 22:37

I suppose making throw a function would allow it to be used with the fat arrow syntax:

Code: Select all

get(this, name, params) {

   if not IsObject(this)
      throw Error("Must be attached to an object.")

   if StrLen(name) == 0
      throw Error("Empty string cannot be passed.")    

   if this.has(name)
      if params.length == 0
         return this[name]
      else
         throw Error("Not sure what to do here")
   else
      throw UnsetItemError(name)
}
It's hard to inspect an object in AutoHotkey to look at its internal structure, so figuring out [paramaters] was harder than it should be
full script
lexikos
Posts: 9780
Joined: 30 Sep 2013, 04:07
Contact:

Re: [V2] trick to read Map values as properties

15 Jul 2022, 01:18

iseahound wrote:
14 Jul 2022, 22:37
I suppose making throw a function would allow it to be used with the fat arrow syntax:
You write that as though the code following it (":") somehow demonstrates your point...
throw Error("Must be attached to an object.")
Why? Other values can have an __Item property.
throw Error("Not sure what to do here")
You want x.y to be equivalent to x["y"]. What do you think happens when x.y[z] is evaluated normally and x.y is just a value property? What about x["y"][z]?
It's hard to inspect an object in AutoHotkey to look at its internal structure, so figuring out [paramaters] was harder than it should be
What's there to figure out?

It is trivial to inspect an object with VSCode, SciTE4AutoHotkey or DebugVars.
aliztori
Posts: 119
Joined: 19 Jul 2022, 12:44

Re: [V2] trick to read Map values as properties

05 Apr 2023, 20:18

Code: Select all

	oMap := Map()
	oMap.CaseSense := "Off"
	oMap.Set("Red", "ff0000", "Green", "00ff00", "Deep Blue", "0000ff")

	oMap.DefineProp("__get", { Call: Get })

	oMap.Default := "Def"

	Get(this, Key, Params) {

		; in this way Return the value of MapObj.Default, if defined:
		try {
			if !Params.Length
				return this[key] ;Or this.Get(Key)
		
			return this[key][Params*]
			
		} catch UnsetItemError
			throw UnsetItemError(Key)
	}

	MsgBox(oMap.asli)

Return to “Tips and Tricks (v2)”

Who is online

Users browsing this forum: No registered users and 7 guests