Final Version v2:
Code: Select all
q := new uber.c
MsgBox % q.test1
q.test2()
q.test3()
try MsgBox % "Ground Level: " ObjRawGet(q, "__class") "`nNumber of Objects: " q.Count()
try MsgBox % "Level -1: " ObjRawGet(q.base, "__class") "`nNumber of Objects: " q.base.Count()
try MsgBox % "Level -2: " ObjRawGet(q.base.base, "__class") "`nNumber of Objects: " q.base.base.Count()
try MsgBox % "Level -3: " ObjRawGet(q.base.base.base, "__class") "`nNumber of Objects: " q.base.base.base.Count()
try MsgBox % "Level -4: " ObjRawGet(q.base.base.base.base, "__class") "`nNumber of Objects: " q.base.base.base.base.Count()
Sleep 2500
class uber {
class a {
__New() {
MsgBox % A_ThisFunc
}
__delete() {
MsgBox % A_ThisFunc
}
test3() {
MsgBox % "This is a method of class a."
}
}
class b {
static extends := "a"
_extends := this.__extends()
__extends(endofunctor := "") {
under := ((___ := this.outer[this.extends].__extends(true)) ? ___ : this.outer[this.extends])
(endofunctor) ? (this.base := under) : (this.base.base := under)
return (endofunctor) ? this : ""
}
outer[p:=""] {
get {
if ((_class := RegExReplace(this.__class, "^(.*)\..*$", "$1")) != this.__class)
Loop, Parse, _class, .
outer := (A_Index=1) ? %A_LoopField% : outer[A_LoopField]
if IsObject(outer)
return (p) ? outer[p] : outer
else
return (p) ? %p% : ""
}
}
test2() {
MsgBox % "This is a method of class b."
}
}
class c {
static extends := "b"
_extends := this.__extends()
__extends(endofunctor := "") {
under := ((___ := this.outer[this.extends].__extends(true)) ? ___ : this.outer[this.extends])
(endofunctor) ? (this.base := under) : (this.base.base := under)
return (endofunctor) ? this : ""
}
outer[p:=""] {
get {
if ((_class := RegExReplace(this.__class, "^(.*)\..*$", "$1")) != this.__class)
Loop, Parse, _class, .
outer := (A_Index=1) ? %A_LoopField% : outer[A_LoopField]
if IsObject(outer)
return (p) ? outer[p] : outer
else
return (p) ? %p% : ""
}
}
test1 := "This is a property of class c."
}
}
Code has been updated and cleaned! New Breakdown:
Code: Select all
; Assume that class "big" is on the same level as "small"
class big {
; static variable to be declared once.
static extends := "small"
; Instance variable are only evaluated when using the "new" operator.
; (Note that the "new" operator calls the __Init() & __New() meta functions.)
_extends := this.__extends()
; parameter = true means that this class has been instantiated.
__extends(endofunctor := "") {
; If the class to be extended also has an __extends() function, call that.
; Note that IsFunc() cannot be used, so a work around is to run the function directly,
; save it to a temporary variable "___" and then check if ___ holds a value.
; We can rewrite the following line as:
; ___ := this.outer[this.extends].__extends(true)
; if (___)
; under := ___
; else
; under := this.outer[this.extends]
; if we remove the temporary variable ___ we would have to call __extends() twice which causes issues.
under := ((___ := this.outer[this.extends].__extends(true)) ? ___ : this.outer[this.extends])
; If the class was instantiated with "new", set the base of the base.
; else if the class was not instantiated, and base is empty and can be set.
(endofunctor) ? (this.base := under) : (this.base.base := under)
; returns this if called via another __extends() function.
return (endofunctor) ? this : ""
}
; see: https://autohotkey.com/boards/viewtopic.php?t=46828
outer[p:=""] {
get {
if ((_class := RegExReplace(this.__class, "^(.*)\..*$", "$1")) != this.__class)
Loop, Parse, _class, .
outer := (A_Index=1) ? %A_LoopField% : outer[A_LoopField]
if IsObject(outer)
return (p) ? outer[p] : outer
else
return (p) ? %p% : ""
}
}
}
EDIT: removed parenthesis
(this.outer)[this.extends] to
this.outer[this.extends] to properly send the argument to the property. Fixes the un-nested case.
EDIT 2: removed circular references, allowing __Delete to work normally.