ObjLength() equiv in v2?

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
guest3456
Posts: 3469
Joined: 09 Oct 2013, 10:31

ObjLength() equiv in v2?

22 Jan 2020, 16:10

in v1 you can do this:

Code: Select all

arr := [1,2,3,4]
arrLen := ObjLength(arr)
msgbox % arrLen
although ObjLength() isn't documented anywhere, save for a brief mention on the main Objects page:
https://www.autohotkey.com/docs/Objects.htm

1. in v1, do all the object.properties have the equivalent ObjProperty(obj) functions?

2. the code above doesn't work because ObjLength() isn't available in v2 and neither is ArrayLength().. is there a way to do it?

HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: ObjLength() equiv in v2?

22 Jan 2020, 16:39

Its a property now so there is no function but you can NumGet which is not recommended since it could easily break your scripts when structure changes.

Code: Select all

arr:=[1,2,3,4]
MsgBox NumGet(&arr,A_PtrSize=8?48:32,"UInt") "=" arr.Length
User avatar
lvalkov
Posts: 58
Joined: 08 Mar 2019, 16:39

Re: ObjLength() equiv in v2?

22 Jan 2020, 17:12

Dynamic properties necessarily have to invoke a function for them to work at all - either get or set, depending. It's only a matter of retrieving a reference to that function.

Code: Select all

Arr := [1, 2, 3, 4]
ObjLength := Array.Prototype.GetOwnPropDesc('Length').Get
len := %ObjLength%(Arr)
MsgBox len
Built-in standalone functions are thereby largely redundant. Most, if not all, of them will likely end up being phased out sooner rather than later.
guest3456
Posts: 3469
Joined: 09 Oct 2013, 10:31

Re: ObjLength() equiv in v2?

22 Jan 2020, 19:30

lvalkov wrote:
22 Jan 2020, 17:12
Dynamic properties necessarily have to invoke a function for them to work at all - either get or set, depending. It's only a matter of retrieving a reference to that function.
thanks, what makes a property "dynamic"?

User avatar
lvalkov
Posts: 58
Joined: 08 Mar 2019, 16:39

Re: ObjLength() equiv in v2?

23 Jan 2020, 00:49

HotKeyIt wrote:
22 Jan 2020, 17:28
MsgBox ObjLength[Arr] works too.
For now. I see no practical reason to recommend the indexing operator for invoking function references as opposed to the standard way of doing so - %fn%().
guest3456 wrote:
22 Jan 2020, 19:30
thanks, what makes a property "dynamic"?
A dynamic property is one that implements a getter, a setter or both, in contrast to value properties, which implement neither.
GetOwnPropDesc's Return Value wrote:If the property is a value property, the return value is an empty string.
guest3456
Posts: 3469
Joined: 09 Oct 2013, 10:31

Re: ObjLength() equiv in v2?

23 Jan 2020, 08:56

gotcha

was trying to figure out the best way to query this in both v1 and v2:

Code: Select all

arr := [1,2,3,4]

arrLen := (A_AhkVersion < "2") ? arr.Length() : arr.Length

LenFunc := (A_AhkVersion < "2") ? "ObjLength" : Array.Prototype.GetOwnPropDesc("Length").Get
arrLen2 := %LenFunc%(arr)

msgbox arrLen
msgbox arrLen2
i'll probably just use the first way

User avatar
lvalkov
Posts: 58
Joined: 08 Mar 2019, 16:39

Re: ObjLength() equiv in v2?

25 Jan 2020, 17:03

"Best" is rather vague and largely dependent on your goals and needs. I can only compare different approaches. At the end of the day, however, you will have to decide whether any of them fits your particular use-case, and if so, which one does it best.

Conditionals

Code: Select all

arrLen := (A_AhkVersion < "2") ? arr.Length() : arr.Length	
+ Simple.
- Overhead of redundant conditionals.
- Code duplication. (Additional overhead if abstracted away with a function wrapper.)

Function Reference

Code: Select all

global LenFunc := (A_AhkVersion < "2") ? "ObjLength" : Array.Prototype.GetOwnPropDesc("Length").Get
arrLen2 := %LenFunc%(arr)
+ Simple.
+ More performant in v2. (Same overhead in v1 as "redundant conditionals".)
- Global namespace pollution.
- Special case handling for force-local functions.
- Danger of accidental overwrites.

Define Length() on Array in v2

Code: Select all

if (A_AhkVersion >= "2")
	Array.Prototype.DefineMethod("Length", Array.Prototype.GetOwnPropDesc("Length").Get)
+ Simple.
+ No source code changes required. (Array.Length() is now v1/v2 compatible.)
+ Similar performance in v1 and v2. (Less overhead than v1's "redundant conditionals".)
- Standard Array interface contamination.
- Possibly brittle. (End-user decides to clear or replace the prototype.)

User-defined function object

Code: Select all

#Warn

class FuncObjBase
{
	__Call(methodName, Args*)
	{
		switch
		{
        case methodName = "": return this.Call(Args*)
        case IsObject(methodName): return this.Call(methodName, Args*)
		}
    }
}

/*
	Every function object template has to inherit from 'FuncObjBase'
	and 'Init()' has to be copied over by the end-user verbatim and
	'className' set to that of the function object. Define a 'Call()'
	*instance* method with the appropriate number of arguments and
	provide a v1/v2 compatible implementation. 
*/
class ObjLength extends FuncObjBase
{
	Init()
	{
		; It is not possible to obtain a reference to the class at the
		; time the static initializers are run, because of which the
		; class name has to be manually hard-coded in by the end-user.
		static className := "ObjLength"
		static ClassObj := %className%
		static invokeSelf := (A_AhkVersion < "2") 
			? ClassObj.Init() 
			: ClassObj.Prototype.Init()

		if (A_AhkVersion < "2")
		{
			; In v1, '%Obj%()' walks the object's base prototype chain and
			; invokes the first defined meta-'__Call()'. No special
			; handling is required apart from erasing the 'Init()' method.
			ClassObj.Delete("Init")
		}
		else
		{
			; In v2, '%Obj%()' always invokes a 'Call()' method and never a
			; meta-'__Call()'. In order to be able to invoke '%ClassObj%()'
			; properly, it is required that a *static*, class method be
			; defined. Create one based on the currently implemented *instance*
			; method, then clean up the interface by erasing the 'Init()' and
			; 'Call()' instance methods.
			ClassObj.DefineMethod("Call", ClassObj.Prototype.GetMethod("Call"))
			ClassObj.Prototype.DeleteMethod("Call")
			ClassObj.Prototype.DeleteMethod("Init")
		}
	}

	Call(Arr)
	{
		; Substitute with a v1/v2 compatible implementation of your choice.
		static fn := (A_AhkVersion < "2")
			? Func("ObjLength") 
			: Array.Prototype.GetOwnPropDesc("Length").Get
		
		return %fn%(Arr)
	}
}

MsgBox % %ObjLength%(Arr) ; v1
MsgBox %ObjLength%(Arr) ; v2
+ Some degree of protection against accidental overwrites (#Warn).
+ No source code changes required. (Use %ObjLength%(Arr) universally.)
- Complex.
- Sub-par v2 performance, abysmal v1 performance.
- BoundFunc interface nonconformity.
- Global namespace pollution.
- Special case handling for force-local functions.
- Brittle.
guest3456
Posts: 3469
Joined: 09 Oct 2013, 10:31

Re: ObjLength() equiv in v2?

25 Jan 2020, 17:54

interesting, thanks for the extra options. i dont really understand the last. i will stick with the first, because this is going into the GDI+ library so i dont want to override prototypes and stuff like that


Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: Draken, macromint, songdg and 68 guests