I've been a software engineer for decades, done a lot of OOP programming. I've done a lot of programming with AutoHotKey as well, very useful tool. I decided to take a look at AutoHotKey's implementation of OOP. Though much is standard, one thing I found was very disappointing. Maybe I'm missing something, but I could not find the answer.
Static variables of a class and instance variables of an instance of a class should never be directly accessible from outside the class or instance thereof. They should only be accessible from within a method or property. Only methods and properties should be accessible from outside the class or instance thereof. That's the great thing about classes, they allow its author to protect the internal static and instance variables from external manipulation.
A property allows the class author to limit the values the user of the class can assign to a class static or instance variable. But, if the user of the class can bypass the property and method protections given it by its author, properties become useless. Methods are useless as well. By useless, I mean in guarding the integrity of the values of the static and instance variables.
Now, perhaps I've missed something, and there is a way to declare variables within a class that cannot be directly accessed from outside the class but accessible by its properties and methods, but I have not found it. Here is an example that demonstrates what I mean:
Code: Select all
class _C
{
static G := {}
;The following only have values when an instance of the class is instantiated:
Var1 := "Non-static variable Var1"
Var2 := "Non-static variable Var2"
Var3 := "Instance Var3 used by property"
Set(name, value)
{
return This.G[name] := value
}
Get(name)
{
return This.G[name]
}
Delete(name)
{
if G.Haskey(name)
G.delete(name)
return
}
SetVar1(value)
{
This.Var1 := value
return
}
GetVar1()
{
return This.Var1
}
Var3Property
{
get
{
return This.Var3
}
set
{
This.Var3 := value
}
}
}
C1 := new _C
C2 := new _C
_Cset := _C.Set("Hi", "Hello there!")
_Cget := _C.Get("Hi")
_Cdir := _C.G[name]
C1.SetVar1("Value for Var1 of C1")
C1.Var2 := "Value for Var2 of C1" ; Direct access (Bad!)!
C2.SetVar1("Class C2 value for Var1")
C2.Var2 := "Class C2 value for Var2" ; Direct access (Bad!)!
C1.Var3Property := "Property Var3 of class 1"
C2.Var3 := "C2 class property instance variable Var3" ; Direct access (Bad!)!
c =
(
C1 := new _C
C2 := new _C
_Cset := _C.Set("Hi", "Hello there!")
_Cget := _C.Get("Hi")
_Cdir := _C.G["Hi"]
C1.SetVar1("Value for Var1 of C1")
C1.Var2 := "Value for Var2 of C1" ; Direct access (Bad!)!
C2.SetVar1("Class C2 value for Var1")
C2.Var2 := "Class C2 value for Var2" ; Direct access (Bad!)!
C1.Var3Property := "Property Var3 of class 1"
C2.Var3 := "C2 class property instance variable Var3" ; Direct access (Bad!)!
)
m := "Code: `n" . c . "`n`nResults:"
. "`nClass _C:"
. "`n`t_C.Get(""Hi""): """ . _C.Get("Hi") . """"
. "`n`t_C.G[""Hi""]: """ . _C.G["Hi"] . """ Can be accessed directly (Bad)!"
. "`n`t_C.GetVar1(): """ . _C.GetVar1() . """"
. "`n`t_C.Var2: """ . _C.Var2 . """"
. "`n`t_C.Var3Property: """ . _C.Var3Property . """"
. "`n`t_C.Var3: """ . _C.Var3 . """"
. "`n"
. "`nInstance C1:"
. "`n`tC1.Get(""Hi""): """ . C1.Get("Hi") . """"
. "`n`tC1.G[""Hi""]: """ . C1.G["Hi"] . """ Can be accessed directly (Bad)!"
. "`n`tC1.GetVar1(): """ . C1.GetVar1() . """"
. "`n`tC1.Var2: """ . C1.Var2 . """Direct access (Bad)!"
. "`n`tC1.Var3Property: """ . C1.Var3Property . """"
. "`n`tC1.Var3: """ . C1.Var3 . """Direct access (Bad)!"
. "`n"
. "`nInstance C2:"
. "`n`tC2.Get(""Hi""): """ . C2.Get("Hi") . """"
. "`n`tC2.G[""Hi""]: """ . C2.G["Hi"] . """ Can be accessed directly (Bad)!"
. "`n`tC2.GetVar1(): """ . C2.GetVar1() . """"
. "`n`tC2.Var2: """ . C2.Var2 . """Direct access (Bad)!"
. "`n`tC2.Var3Property: """ . C2.Var3Property . """"
. "`n`tC2.Var3: """ . C2.Var3 . """Direct access (Bad)!"
MsgBox %m%