... means that you have to test every key for the value "base" and, if found, use a special assignment, such as ObjRawSet or Object.SetCapacity.
Not true. You can choose to do it that way, but it's not the only or best way.
If your object is intended to be used only for storage of arbitrary keys, you presumably would not want any specialised properties (whether built-in or defined by you). In that case, there's no need to check for "base"; just use ObjRawSet for all keys.
The stock object is a "multi-purpose tool" and as such, is not perfect for every purpose. It is designed with the flexibility for
you to make an object which behaves how you want (with some restrictions, like
x.y and
x["y"] must always be equivalent). So if you don't want
x["base"] (or
x.base) to return x's base, override it.
Code: Select all
class AArray {
base {
set {
ObjRawSet(this, "base", value)
}
/* ; Use this to override the default value.
get {
; An empty 'get' is the same as 'return ""'.
}
*/
}
}
a := new AArray
k := "base"
MsgBox % a.base = AArray ; true
a[k] := "Hello." ; overrides 'base'
MsgBox % a[k] ; Hello.
This disables
a.base and
a["base"] only after an assignment is made. If you uncomment
get, the override will be immediate (when the object is constructed) and permanent. A much shorter way of achieving something similar is
ObjRawSet(a, "base", "") during initialisation of
a. However, that method has drawbacks: 1) the value is present in the object, so
ObjHasKey(a, "base") returns
true and enumerators/the for-loop will include it; 2)
ObjDelete(a, "base") will revert the behaviour.
On a related note, if you're storing arbitrary keys which could match method names (such as
"HasKey"), you may become unable to call those methods. JavaScript and some other scripting languages also suffer from that problem. However, in AutoHotkey you can override that behaviour by redirecting the values to another object with the __Get and __Set meta-functions. (You would also need to override any built-in methods which you want to support.)
Code: Select all
class BArray {
__New() {
ObjRawSet(this, "data", {})
}
__Get(k) {
return this.data[k]
}
__Set(k, v) {
ObjRawSet(this.data, k, v)
return v
}
HasKey(k) {
return ObjHasKey(this.data, k)
}
}
b := new BArray
b.HasKey := 42
MsgBox % b.HasKey ; 42
MsgBox % b.HasKey("HasKey") ; true
While we're on this topic, I think it's worth mentioning that objects are always case-insensitive. If you don't want that behaviour, there currently isn't a built-in solution. You can use a COM object such as
ComObjCreate("Scripting.Dictionary") (this is the easiest), encode string keys (e.g. to hex/base64), or roll your own complete data structure. Whatever method you use, you can hide it away in a class if you wish.