object classes: redefine __Set() temporarily / general queries

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily

16 Jan 2018, 15:22

- Details? It's not a technical discussion per se. I'm going to rewrite CUSTOM CLASSES V. FUNCTIONS now, shuffle the content about a bit, and make it a bit clearer. [EDIT: Rewrite done.]
- Thanks for your latest responses. Btw re. communication, quite often person A gives a subtle hint about something to person B, half the time, person B doesn't understand what was meant, or forgets what was meant when they reread the thread, and almost nobody else who reads the thread gets it.
- [EDIT:] Re. the example and the number of parameters, yes, that's right, thanks for pointing it out (I hadn't noticed it). The key thing that drew my attention was this, which I suppose could be used in a custom __Set() meta-function, it gives each new object a specific class by setting the base, and it is an approach that is simpler than others.
x[p1] := new x.base
- [EDIT:] When storing keys in one or two subkeys of an array, it would be good to have a name for that, maybe a 'clash avoidance' class, or a '__Get forcer' class that always forces __Get() to be used when retrieving keys. Although wouldn't that sort of approach only be appropriate for arrays with a restricted number of dimensions, or a certain type of hierarchy.

- [EDIT:] I'll have a check over my queries list, before starting a new thread on enumerators.
- Terminology, keys:
obj[1] := "a" ;a key with a numeric name with a string value?
obj["a"] := 1 ;a key with a string name with a numeric value?
What is a 'string key' or a 'numeric key', or are they ambiguous terms?
- Terminology, subclass v. nested class:
I was interested in any uses for subclasses/nested classes, other than for use with an enumerator.
Question About Classes - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/8552 ... ntry545206
- Terminology, method v. meta-function:
Is the distinction that if you overwrite a method, with a custom method, the original functionality is lost, whereas if you overwrite a meta-function, with a custom meta-function, the original functionality is lost only if you use 'return' somewhere inside it. Or is the distinction something else?

- Btw I was thinking that maybe built-in and custom arrays need some kind of Push/Insert method, to allow you to do something like oArray.InsertEx({a:1,b:2,c:3}), to add keys to an existing array.
- Btw also, cheers for your object investigator script for AHK v2:
object classes: redefine __Set() temporarily - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 33#p194533
Related to that, this could also be interesting:
[Lib] ObjDump / ObjLoad - Object Backup - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=3573
- Btw plus, your 2 meta-functions differ, but they look virtually identical, is there a key difference in practice?

Code: Select all

__set(k,p*){
	v := p.pop() . this.__a
	return this.__o[k,p*] := v
}
__set(p*){
	v := p.pop() . this.__a
	return this.__o[p*] := v
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily

17 Jan 2018, 06:59

is there a key difference in practice?
Indeed there is a key difference of value in practice :lol:
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily

17 Jan 2018, 08:17

- @Helgef: Do you do much with properties, do you have any good example classes that use them? I didn't find very much in the documentation.
- [EDIT:] I found a good properties example.
Variables as references/pointers? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 660#p41660
- You stated before that .base is a property, so I suppose that it's the one property that built-in AHK arrays have.

Code: Select all

q::
oArray := new MyClassProperty
oArray.Property := "hello"
MsgBox, % oArray.Property
MsgBox, % JEE_ObjHasMethodOrProperty(oArray, "Property")
MsgBox, % JEE_ObjHasMethodOrProperty(oArray, "Propertyx")
MsgBox, % oArray.PropertyValue

vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey "`t" vValue "`r`n"
MsgBox, % vOutput

vOutput := ""
for vKey, vValue in oArray.base
	vOutput .= vKey "`t" vValue "`r`n"
MsgBox, % vOutput
return

;e.g. MsgBox, % JEE_ObjHasMethodOrProperty(oArray, "MyProperty")
JEE_ObjHasMethodOrProperty(oArray, vProperty)
{
	for vKey in oArray.base
		if (vKey = vProperty)
			return 1
	return 0
}

class MyClassProperty
{
	Property
	{
		get
		{
			MsgBox, % A_ThisFunc
			return this.PropertyValue
		}
		set
		{
			MsgBox, % A_ThisFunc
			MsgBox, % "value: " value
			return this.PropertyValue := value
		}
	}
	Method()
	{
	}
}
- [Links re. properties.]
Objects
https://autohotkey.com/docs/Objects.htm ... s_property
Objects
https://autohotkey.com/docs/Objects.htm#Custom_Classes

- (Re. 'a key difference of value in practice'.) Btw this isn't the Code Puzzle Thread hehe. I'm trying to shed light on things, and not be cryptic.
- Btw one interesting tidbit I discovered, if you pass an object ByRef, it doesn't alter the reference count.
- [EDIT:] I've basically covered all the material (enumerators aside), that I intended to, in this thread. So if anyone has any interesting links or material, on the subjects discussed here, please post some links. I might use some of that material for my tutorial.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily

17 Jan 2018, 19:24

- Objects to and from pointers, based on this example:
Dereferencing object pointer - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/6527 ... ntry412181
- I think that it really helps to have a ref count function, to help ensure that you release any references where necessary. It's actually the first time I've done this and felt sure that I knew how the ref counts were being handled.

Code: Select all

q:: ;obj to pointer, pointer to obj
oArray := ["a", "b", "c"]
	MsgBox, % JEE_ObjRefCount(oArray)
pArray := Object(oArray)
	MsgBox, % JEE_ObjRefCount(oArray)
oArray2 := Object(pArray)
	MsgBox, % JEE_ObjRefCount(oArray)
ObjRelease(pArray)
	MsgBox, % JEE_ObjRefCount(oArray)
MsgBox, % oArray2.2
oArray := ""
	MsgBox, % JEE_ObjRefCount(oArray2)
oArray2 := ""
return

JEE_ObjRefCount(ByRef oObj)
{
	;note: if you didn't use ByRef, this function itself would increase the ref count
	;note: this technique is undocumented, and may not work in future (tested on AHK v1.1)
	return NumGet(&oObj + A_PtrSize)
}
- I had experimented with objects to/from pointers in the past, but had since forgotten how to do it.
- Going over it now has made something really clear to me, that had puzzled me in the past.
- I had been confused by the Object function, when I first looked into it, because you could use it in multiple different ways, I was unclear on what the full list was.

Code: Select all

obj := Object() ;create object, specify keys/values
obj := Object(k, v) ;create object, specify keys/values
obj := Object(k1, v1, k2, v2, ...) ;create object, specify keys/values
obj := Object(ptr) ;create a variable for an object, based on a pointer to an existing object
ptr := Object(obj) ;get pointer to (address of) an object, based on an existing object
- I generally think of the Object function as accepting an even number of key/value pairs, or nothing, to specify an empty array. However, if you specify exactly 1 parameter, it has a special meaning:
- 1 parameter: it's a pointer to (address of) an object, or a variable representing an object (presumably the function does something like IsObject to determine which it is)
- 2n parameters (n >= 0): it's a list of keys/values

- So basically, the issue is that the Object function is 3 functions in one. E.g. some possible names: ObjCreate, ObjFromPtr, ObjGetPtr.
- If ObjFromPtr and ObjGetPtr were separate functions (I don't mind what the names would be), then it would make debugging easier, and you could tell whether the scriptwriter intended obj var from ptr or ptr from obj var (because sometimes the variable names might be misleading, or someone might have used a function incorrectly).
- We're being clever with functions cf. NumGet/NumPut and StrGet/StrPut with optional parameters.
- Further examples of this are the custom ObjDump / ObjLoad functions, linked to above. That write to/from a variable/file based on the order of the parameters, in quite a surprising unintuitive way.
Last edited by jeeswg on 17 Jan 2018, 20:28, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily

17 Jan 2018, 20:21

- I was experimenting with a class re. parents.

Code: Select all

q:: ;parent class
oArray := new MyClassParent
oArray["a", "b", "c", "d", "e", "text"] := 1
MsgBox, % oArray.a.b.c.d.e.text

MsgBox, % JEE_ObjFromPtrList(oArray.a.b.c.d.e.parent)
MsgBox, % JEE_ObjFromPtrList(oArray.a.b.c.d.parent)
MsgBox, % JEE_ObjFromPtrList(oArray.a.b.c.parent)
MsgBox, % JEE_ObjFromPtrList(oArray.a.b.parent)
MsgBox, % JEE_ObjFromPtrList(oArray.a.parent)
MsgBox, % JEE_ObjFromPtrList(oArray.parent)

MsgBox, % oArray.a.b.c.d.e.parentname
MsgBox, % oArray.a.b.c.d.parentname
MsgBox, % oArray.a.b.c.parentname
MsgBox, % oArray.a.b.parentname
MsgBox, % oArray.a.parentname
MsgBox, % oArray.parentname
return

JEE_ObjFromPtrList(pArray, vSep:=" ")
{
	vOutput := ""
	for vKey, vValue in Object(pArray)
		vOutput .= vKey vSep vValue "`r`n"
	return SubStr(vOutput, 1, -2)
}

class MyClassParent
{
	__Set(oParams*)
	{
		vValue := oParams.Pop()
		vKey := oParams.Pop()
		if !oParams.Length()
			return ObjRawSet(this, vKey, vValue)
		oParams2 := {}
		for vKey2, vValue2 in oParams
		{
			if (A_Index = 1) && !this.HasKey(vValue2)
			{
				ObjRawSet(this, vValue2, new MyClassParent)
				ObjRawSet(this[vValue2], "ParentName", "object")
				ObjRawSet(this[vValue2], "Parent", Object(this))
			}
			else if !this[oParams2*].HasKey(vValue2)
			{
				ObjRawSet(this[oParams2*], vValue2, new MyClassParent)
				obj := this[oParams2*]
				ObjRawSet(obj[vValue2], "ParentName", oParams2[oParams2.Length()])
				ObjRawSet(obj[vValue2], "Parent", Object(obj))
			}
			oParams2.Push(vValue2)
		}
		return ObjRawSet(this[oParams2*], vKey, vValue)
	}
}
- [EDIT:] As happens with classes, there may be a simpler alternative approach for what you want to do, e.g. simply using a built-in array.

Code: Select all

q:: ;store dirs as keys of an array
oArray := {}
vDir1 := A_ScriptDir
Loop, Files, % vDir1 "\*", DR
{
	vDir := A_LoopFileFullPath
	oArray[vDir] := {}
	Loop, Files, % vDir "\*", F
	{
		vName := A_LoopFileName
		oArray[vDir].Push(vName)
	}
}
for vKey, vValue in oArray
{
	vOutput := ""
	for _, vValue2 in vValue
		vOutput .= vValue2 "`r`n"
	MsgBox, % vKey "`r`n`r`n" vOutput
}
MsgBox, % "done"
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 07:41

I'm trying to shed light on things, and not be cryptic.
That is admirable :D.

I have a hard time to keep up with all the queries, separate topics would be preferable, it would also increase the chance that others would be interested in reading and answering. I'll consider commenting on a few things later.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 09:07

- I sort of agree with you, re. separate topics. I was in two minds.
- One reason I decided to keep it in one topic, is because everything's so interconnected, and it's easier to find things if they're all in one topic. And also, if anything emerged as particularly complicated, you, I, or someone else, could start a separate thread.
- I do intend to start a separate thread re. enumerators.
- I think it underlines how important good tutorials and documentation are for objects/object classes, I appreciate it's very difficult for anyone to write a good, clear tutorial on such a broad topic. And because there isn't already such a tutorial (although there have been tutorials that have definitely helped me), it's meant so much research and questions for me to resolve, an A-Z of objects (my new book: The AbjectZ).

==================================================

- I had some queries re. reference counting and the 3-in-1 function nature of the Object function, where fortunately I've managed to clear everything up, both in previous posts in this thread, and in this post.
conversion logic, v1 = -> v1 := -> v2, two-way compatibility - Page 4 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 36#p138636
- I now have what I believe is a function that performs reference counting, but that does not use undocumented techniques. See JEE_ObjRefCount2.
- It appears that the reference counting approaches for built-in AHK arrays, also work with COM objects.

Code: Select all

q:: ;test reference counting
oArray := ["a", "b", "c"]
	MsgBox, % JEE_ObjRefCount(oArray)
pArray1 := &oArray ;ref count unchanged
	MsgBox, % JEE_ObjRefCount(oArray)
pArray2 := Object(oArray) ;ref count increased
	MsgBox, % JEE_ObjRefCount(oArray)
	MsgBox, % pArray1 " " pArray2

MsgBox

;equivalent:
;pArray := &oArray, ObjAddRef(pArray)
;pArray := Object(oArray)

oArray := ["a", "b", "c"]
	MsgBox, % JEE_ObjRefCount(oArray)
pArray := &oArray, ObjAddRef(pArray)
	MsgBox, % JEE_ObjRefCount(oArray)
pArray := Object(oArray)
	MsgBox, % JEE_ObjRefCount(oArray)
oArray := ""
return

w:: ;test reference counting
oArray := ["a", "b", "c"]
	MsgBox, % JEE_ObjRefCount(oArray) ;1
MsgBox, % ObjAddRef(&oArray) ;2
	MsgBox, % JEE_ObjRefCount(oArray) ;2
MsgBox, % ObjRelease(&oArray) ;1
	MsgBox, % JEE_ObjRefCount(oArray) ;1
MsgBox, % JEE_ObjRefCount2(oArray) ;1

MsgBox

oArray := ["a", "b", "c"]
MsgBox, % JEE_ObjRefCount(oArray) " " JEE_ObjRefCount2(oArray)
oArray2 := oArray
MsgBox, % JEE_ObjRefCount(oArray) " " JEE_ObjRefCount2(oArray)
oArray := oArray2 := ""
return

;==================================================

e:: ;get ref count, com object
oWB := ComObjCreate("InternetExplorer.Application")
MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
oWB2 := oWB
MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
oWB := oWB2 := ""
return

JEE_ObjRefCount(ByRef oObj)
{
	;note: if you didn't use ByRef, this function itself would increase the ref count
	;note: this technique is undocumented, and may not work in future (tested on AHK v1.1)
	return NumGet(&oObj + A_PtrSize)
}

JEE_ObjRefCount2(ByRef oObj)
{
	;note: if you didn't use ByRef, this function itself would increase the ref count
	ObjAddRef(&oObj)
	return ObjRelease(&oObj)
}
- I now have what I believe is a function that performs reference counting, but that does not use undocumented techniques. (I also provide my original function that does use undocumented techniques.)

Code: Select all

JEE_ObjRefCount(ByRef oObj)
{
	;note: if you didn't use ByRef, this function itself would increase the ref count
	;note: this technique is undocumented, and may not work in future (tested on AHK v1.1)
	return NumGet(&oObj + A_PtrSize)
}

JEE_ObjRefCount2(ByRef oObj)
{
	;note: if you didn't use ByRef, this function itself would increase the ref count
	ObjAddRef(&oObj)
	return ObjRelease(&oObj)
}
- Re. pointers and ref counts:

Code: Select all

;the following are equivalent:
pArray := &oArray, ObjAddRef(pArray)
pArray := Object(oArray)

;note:
pArray := &oArray ;this doesn't increase the ref count
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 11:37

my new book: The AbjectZ
:lol: :thumbup: Nice one.

Code: Select all

JEE_ObjRefCount2
That would be the usual way. You should never need that for anything else than debugging, and only in rare cases.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 12:11

Well, ComObjEnwrap and ComObjUnwrap had been confusing me for a long time. 'Unwrap' sounds like it's removing something, but yet information is being retrieved, and the reference count is *increased*.

Code: Select all

;note: in all of these examples, the reference count is increased by 1
;note: each pair of lines is functionally equivalent

;obj from ptr (built-in AHK array)
obj := Object(ptr)

;obj get ptr (built-in AHK array)
ptr := Object(obj)
ptr := &obj, ObjAddRef(ptr)

;obj from ptr (COM object)
obj := ComObject(9, ptr, 1), ObjAddRef(ptr)
obj := ComObjEnwrap(ptr) ;deprecated (AHK v1 only)

;obj get ptr (COM object)
ptr := ComObjValue(obj), ObjAddRef(ptr)
ptr := ComObjUnwrap(obj) ;deprecated (AHK v1 only)
'The circle is now complete.'
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 13:45

Further points re. objects/pointers:
ComObjActive()
https://autohotkey.com/docs/commands/ComObjActive.htm
Known limitation: Each time a COM object is wrapped, a new wrapper object is created. Comparisons and assignments such as obj1 == obj2 and array[obj1] := value treat the two wrapper objects as unique, even though they contain the same COM object.
Objects
https://autohotkey.com/docs/Objects.htm ... n_Pointers
Note that the Object() function can be used even on objects which it did not create, such as COM objects and File objects.
==================================================

- Some tests on COM objects.
- Applying ObjAddRef to a pointer does not appear to change the reference count for an object. Is this related to 'Each time a COM object is wrapped, a new wrapper object is created'?
- Creating another variable for an existing COM object does appear to change the reference count.
- Also, these appear to give different values: ptr := ComObjUnwrap(obj) and ptr := &obj. Is that related to 'Each time a COM object is wrapped, a new wrapper object is created' also?

Code: Select all

q:: ;get ref count, COM object
oWB := ComObjCreate("InternetExplorer.Application")
oWB.visible := True
oWB.navigate("https://autohotkey.com/")
while oWB.busy || oWB.ReadyState != 4
	Sleep, 10
MsgBox, % oWB.document.url
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)

ptr1 := ComObjValue(oWB), ObjAddRef(ptr)
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)

ptr2 := ComObjUnwrap(oWB) ;deprecated (AHK v1 only)
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)

MsgBox, % ptr1 " " ptr2 " " &oWB
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)

oWB1 := ComObject(9, ptr1, 1), ObjAddRef(ptr)
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
	MsgBox, % "1: " JEE_ObjRefCount(oWB1) " " JEE_ObjRefCount2(oWB1)
oWB2 := ComObjEnwrap(ptr2) ;deprecated (AHK v1 only)
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
	MsgBox, % "2: " JEE_ObjRefCount(oWB2) " " JEE_ObjRefCount2(oWB2)
ObjAddRef(ptr1)
ObjAddRef(ptr1)
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
	MsgBox, % "1: " JEE_ObjRefCount(oWB1) " " JEE_ObjRefCount2(oWB1)
MsgBox, % oWB.document.url "`r`n" oWB1.document.url "`r`n" oWB2.document.url
oWB3 := oWB
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
oWB4 := oWB
	MsgBox, % JEE_ObjRefCount(oWB) " " JEE_ObjRefCount2(oWB)
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 17:36

- A basic example re. extending a class.
E.g. MyClassPart1 is the superclass, and MyClassPart2 is the subclass.
class MyClassPart1
class MyClassPart2 extends MyClassPart1
- Where new MyClassPart1 creates a MyClassPart1 object as usual.
- Where new MyClassPart2 creates an object that has the features of both MyClassPart1 and MyClassPart2. If they have overlapping methods, for example, those of MyClassPart2 take precedence.

Code: Select all

q:: ;extend class
oArray1 := new MyClassPart1
oArray2 := new MyClassPart2
vText1 := oArray1.Method1()
. "`r`n" oArray1.Method2()
. "`r`n" oArray1.Method3()
vText2 := oArray2.Method1()
. "`r`n" oArray2.Method2()
. "`r`n" oArray2.Method3()
MsgBox, % vText1 "`r`n===============`r`n" vText2
return

class MyClassPart1
{
	Method1()
	{
		return A_ThisFunc
	}
	Method2()
	{
		return A_ThisFunc
	}
}

class MyClassPart2 extends MyClassPart1
{
	Method2()
	{
		return A_ThisFunc
	}
	Method3()
	{
		return A_ThisFunc
	}
}
- I would be interested in any specific/general examples of where *nested* classes are useful, other than for enumerators.
- Note: the example in this script is not of a nested class, the example in this script is of a superclass and a subclass.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 17:50

Note that the extended class can call a method in its base with the using the base keyword, eg,

Code: Select all

class MyClassPart2 extends MyClassPart1
{
	Method2()
	{
		
		return A_ThisFunc "`t" base.Method2()
	}
	; ...
where base.f() means this.base.f.call(this)

Nested classes are useful at least for encapsulating and organising purposes, you can make a class without creating another super-global variable. You can look at classGDIp.ahk, it is a very natural to organise it that way.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

18 Jan 2018, 20:09

CUSTOM CLASSES V. FUNCTIONS (REVISITED)

- The code in the Gdip class looks very well laid out, and is probably great code, but I would much rather stick with individual functions. So by that logic, it doesn't feel like a natural use of nested classes to me, but thanks for sharing.
- For me, with each Gdip function, I can inspect them individually. Suddenly, with a class, you feel like you have to understand the entire class, just to understand one 'function' (and even the input/output points become obscured). And suddenly, *methods* are needed for everything, when they weren't needed before. How did we manage, doing image manipulations, without object classes that have __Get()/__Set() methods. Also, you can easily pull individual functions from a library, but not sections of code from across a class.
- Earlier in this thread, I suggested a parent class, and then a much simpler alternative using a built-in array. So I'm always ready to use a class, if I have to, but usually, I don't have to, and it's better not to.
- I do wonder about the JSON library by Coco that I use, possibly the only thing I use that uses classes. Would it be better as separate functions or not? Hmm, I liked the FTP class also but again, is it better that way? For Example, with clipboard and GUI libraries, I've gone from classes to functions, and found that to be much the better approach. And now. seeing my favourite libraries (Acc and Gdip) being considered as classes, I appreciate the original libraries more.
- I will try writing some classes for file/registry looping.
- Can a Gdip class be written around the existing Gdip functions?
- It's like you wake up suddenly one day, look around, and think: since when did coding become so unnecessarily complicated?

==================================================

CODE PUZZLE THREAD: ENUMERATORS

- I had planned that I would look at the Code Puzzle Thread page, as the last thing to do before moving onto enumerators, which is what I'm now doing.
- Btw the Code Puzzle Thread had an excellent example on enumerators, by someone, Puzzle 2, which I will refer to in the enumerators thread, when I start it. It's really made the whole thing absolutely clear to me, for the first time, how _NewEnum and Next work.
Code Puzzle Thread - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 85#p121585

==================================================

OTHER POINTS

[subclasses]
- @Helgef: Thanks for the base example. It's the one thing my example needed, I might add it in in some form.

[function objects]
- I will do a post here on 'function objects' etc.

[__Delete() and parameters]
- Any idea re. this? I don't think it's mentioned in the documentation.
Code Puzzle Thread - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 66#p172966
__Delete won't work with a function expecting two or more mandatory arguments.
- Using __Delete() for when a script closes, is a great technique, and the shell hook example is great.

[releasing a reference]
- There is an interesting example here re. releasing a reference.
Code Puzzle Thread - Page 5 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 60#p193560
Code Puzzle Thread - Page 4 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 48#p192848
- Btw are there any interesting links re. circular references?
Last edited by jeeswg on 19 Jan 2018, 04:32, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily / general queries

19 Jan 2018, 04:29

How did we manage, doing image manipulations, without object classes that have __Get()/__Set() methods.
__get and __set isn't what is important about classes. I'm not interested in debating classes vs functions, it is not meaningful, each has its place, and can be used togheter. You could start another thread if you are interested in that sort of debate, I don't think it would lead to anything.
- Btw the Code Puzzle Thread had an excellent example on enumerators
You linked to my solution, it is horrible :lol:. It was a good puzzle though. The example on the for-loop page is pretty clear imo. The enumerator object page uses enum[k,v] instead of enum.next(k,v), which might not be the best choice though. The last puzzle (9) in the code puzzle thread is a better example imo.
__Delete won't work with a function expecting two or more mandatory arguments.
No function works when you do not call it with the required parameters, there wouldn't be a puzzle if AHK had thrown a run time exception, and there is no puzzle in v2, it gives the error :thumbup:. It is exactly this the sub-classing arrays of arrays example relies on, as we spoked about earlier in this thread.
- Using __Delete() for when a script closes, is a great technique
Not really ;). Using onexit is recommended. You can use __delete when the clean up is only related to the object being deleted. You cannot rely on other variables in the script still being available when __delete is called when the program is shutting down, with onexit, you can. Example, for the sake of being overly clear ;)

Code: Select all

o := ["important stuff"]
oo := {base:{__delete:"f"}}
onexit("f")
f(this){
	global o
	msgbox(isobject(o) ? o.1 : "it is gone...")
}
Even the puzzle is relying on things not being documented (afaik), it relies on the msgNum variable still being available, it is, by luck. Here is a less lucky example,

Code: Select all

f(this){
	static a := "str"
	static b := {base:{__delete:"f"}}
	msgbox(a)	; lucky
}
g(this){
	static a := ["str in object"]
	static b := {base:{__delete:"g"}}
	static c := ["str in object"]
	msgbox(isobject(a) "`n" isobject(c)) ; unlucky `n lucky
}
The potential for problems are great. I have learned by making the mistake, it is not fun, and I have made the mistake even after learning :oops: :facepalm:.

Cheers. :wave:
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

19 Jan 2018, 05:05

CUSTOM CLASSES V. FUNCTIONS (ADDENDUM)

- Yes, now is not the time for the classes v. functions debate. I'll mention it to people now, and then, after a year, people will start to realise the truth of what I'm saying and at least halfway agree with me.
- One would hope that the cleverer one is at using classes, the cleverer one is at not using classes. I.e. that one is sceptical and not fad-prone. I do feel that they regularly create something of a debugging nightmare, where none is needed.
- Classes of under 30 lines, and AutoHotkey hacks that make use of classes, have their uses though. And classes that are built around stand-alone functions are to be encouraged.
- As my knowledge of object classes is becoming more precise, I am actually becoming more sceptical about them. Red flags. Warning signs. My instincts kicking into overdrive. This is not the way to code.
- Btw I'm not being po-faced serious there, although there is some truth to be had hehe.

OTHER POINTS

- Whew, well I've now gone through Code Puzzle Thread, an excellent resource re. objects.
- I'm not sure how many parameters __Delete() allows, a fixed amount, variadic? (I did tests in AHK v1/v2.)
- Also is it possible to fix the 'sub-classing arrays of arrays' example? (I tried.)

- Omg, the lucky/unlucky example above, even more problems down the objects rabbit hole.

- This is a good point, seeing Next being used, in the documentation, as you did, would have helped, I'll include both in my examples.
The enumerator object page uses enum[k,v] instead of enum.next(k,v)
- Nice use of emoticons as ever.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: object classes: redefine __Set() temporarily / general queries

19 Jan 2018, 05:41

well I've now gone through Code Puzzle Thread, an excellent resource re. objects.
It doesn't have to be about objects, you are free to submit any non-object related puzzle ;).
I'm not sure how many parameters __Delete()
AHK calls it passing only one variable, that is this, which is a reference to the object being deleted. If you specify a regular script function it must accept one parameter, it can have any amount of excessive paramters, but they need to have default values or being variadic. Eg,

Code: Select all

f(this,x:=1,y:=2, z*){
}
is fine. If you use a method, this is implicit, then

Code: Select all

class x {
	__delete(x:=1,y:=2, z*){
	}
}
is fine.
is it possible to fix the 'sub-classing arrays of arrays' example? (I tried.)
Of course ;) What did you try?
- Nice use of emoticons as ever.
Thank you, I try my best ☕.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

21 Jan 2018, 15:48

Redefine an array to return 0 if a key is not found.

Code: Select all

q:: ;redefine array to return 0 if key not found
oArray := {}
oArray.a := 1
MsgBox, % oArray.a " - " oArray.b
MsgBox, % oArray.c + 1
oArray.d++
MsgBox, % oArray.d
oArray.e += 3
MsgBox, % oArray.e

oArray.base := {"__Get":"ReturnFalse"}
MsgBox, % oArray.a " - " oArray.b
MsgBox, % oArray.c + 1
oArray.f++
MsgBox, % oArray.f
oArray.g += 3
MsgBox, % oArray.g
return

ReturnFalse()
{
	return 0
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

27 Jan 2018, 10:53

- Based on code re. GetKeyState, I was curious re. creating a key with a blank string name.
conversion logic, v1 = -> v1 := -> v2, two-way compatibility - Page 7 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 43#p196943
- I'm not sure if there are other ways.

Code: Select all

q:: ;create key with blank name
obj := {}
obj[""] := 1
MsgBox, % obj[""]
obj := ""

obj := {"":2}
MsgBox, % obj[""]
obj := ""

var := ""
obj := {(var):3}
MsgBox, % obj[""]
obj := ""
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
derz00
Posts: 497
Joined: 02 Feb 2016, 17:54
Location: Middle of the round cube
Contact:

Re: object classes: redefine __Set() temporarily / general queries

27 Jan 2018, 11:10

boy, just looking at the last few posts makes me wonder at the complexity and confusion of AHK syntax vs Python :P
try it and see
...
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: object classes: redefine __Set() temporarily / general queries

28 Jan 2018, 15:12

- @derz00: Haha, I don't feel that the AHK expression-style or object syntax is bad in any way. Are you saying Python is better somehow?

- @Helgef: I don't particularly plan on asking anything more on this thread, although I might do, when I try to complete the first version of my object classes tutorial.
- The 'Some tests on COM objects' is giving me some concern however, basically, ref counting seems to be quite different for AHK arrays and COM objects, and it differs when applied to objects/pointers, and I'm not sure of the full details.
- I've posted what I had to say on 'function objects' in a separate thread, and I plan to finish with a new thread on enumerator objects.
objects: function object queries - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=43447
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 265 guests