AutoHotkey Community

It is currently May 27th, 2012, 12:00 am

All times are UTC [ DST ]




Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 1036 posts ]  Go to page Previous  1 ... 12, 13, 14, 15, 16, 17, 18 ... 70  Next
Author Message
 Post subject:
PostPosted: October 2nd, 2009, 4:35 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Why is set function not launched when a key is removed?
Is there another way to do that?
Code:
e:=Object("base", object("__Set","set"))
e.1:="test"
e.1:=""
MsgBox % "MaxIndex: " e._MaxIndex()
ExitApp

set(clr,name,val){
   MsgBox name: %name%`nval: %val%
}

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 2nd, 2009, 4:41 pm 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
HotKeyIt wrote:
Why do you want to do that by address?

so that something like this will work
Code:
e := object()
e.base.MsgBox := "MsgBox"
cb := RegisterCallback( "TestObj_cb","","",&e)
e.text := "Some Text Goes Here"
DllCall(cb)
return


TestObj_cb(){
o := (A_EventInfo) ; contains address to object
If IsObject(o)
   {
   o.MsgBox()
   }
}

MsgBox(obj){
   MsgBox % obj.text
}

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 2nd, 2009, 7:05 pm 
Offline

Joined: July 9th, 2009, 9:25 pm
Posts: 120
AHK_L removes leading zeros when returning a var:
Code:
; AHK Output: 0000, AHK_L Output: 0
Msgbox, % x()

x(){
   hex = 0000
   Return hex ; 'Return 0000' or 'Return hex . ""' works fine
}


This bug messes up HexView/Mem_Dump's output.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 2nd, 2009, 7:44 pm 
Offline

Joined: March 27th, 2008, 2:14 pm
Posts: 700
ahklerner: I think this would have more to do with a general variable Alias() function than objects specifically, though it might be especially nice for objects. Personally, I would love this functionality with regular variables as well as objects.
Code:
Alias(newVar, A_EventInfo+0) ; possible syntax for your example

_________________
Scripts - License


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 2nd, 2009, 9:00 pm 
Offline

Joined: March 27th, 2008, 2:14 pm
Posts: 700
Now that we have objects, a handy function definition sugar would be to allow the last param in the definition be passed as an object that contains all remaining params from the caller.

Python has a similar syntax.

Here's an example using Python's syntax for defining a param that takes a variable number of arguments:
Code:
myfunc(100,200,"test",-5)

myfunc(a, b, *extra){
  ; "Before the variable number of arguments, zero or more normal arguments may occur."
  ; a = 100
  ; b = 200
  ; extra == Object(1, "test", 2, -5)
}


Edit: It would be especially handy for the object __call meta function, since it handles an arbitrary number of params:
Code:
obj := Object()
obj.base.__call := "MyCall"
obj.name := "My Object"

obj.RandomFunc(param1, "extra param", "foobar", 4)

MyCall(obj, func, *params) {
   MsgBox % obj.name " called: " func
   loop % params._MaxIndex()
      MsgBox % params[A_Index]
}


Edit: A somewhat similar idea, perhaps the "opposite" of the above, is to dynamically turn an object into multiple params.
Code:
a := Object()
a[1] := "banana"
a[2] := "cherry"
a[3] := "date"

Fruits( "apple", a* )  ;syntax to expand numbered fields into sequential params in the definition

Fruits( first, second, third, fourth ) {
  MsgBox, The fruits are: %first%, %second%, %third%, and %fourth%
}

A note on syntax: While the function may allow the use of the asterisk inside it's parameter definition to denote this idea, this wouldn't work in a call since *Expression is already taken. Perhaps the syntax Object* would work, since it avoids the *Expression conflict. It's also a compelling syntax idea because it is intuitively the opposite of the previous idea (turning multiple params into one object).

_________________
Scripts - License


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 2nd, 2009, 11:32 pm 
Offline

Joined: July 9th, 2009, 9:25 pm
Posts: 120
Another bug:
Code:
obj1 := Object()
obj1.prop := Object()

Msgbox, % obj1       ; works as expected
Msgbox, % obj1.prop  ; crash
Msgbox, This never executes.



And +1 to everything infogulch said :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 3rd, 2009, 7:35 am 
Offline

Joined: February 22nd, 2009, 7:51 pm
Posts: 47
Location: Poland
temp01 wrote:
AHK_L removes leading zeros when returning a var:
Code:
; AHK Output: 0000, AHK_L Output: 0
Msgbox, % x()

x(){
   hex = 0000
   Return hex ; 'Return 0000' or 'Return hex . ""' works fine
}


This bug messes up HexView/Mem_Dump's output.


So this is what broken the Morse function! I'll update as soon as it is fixed.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 3rd, 2009, 9:42 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
Quote:
Revision 33 - October 3, 2009
  • Fixed: Local variables were not automatically freed for functions which return objects or pure numbers.
    ("CO" in temp01's example was not freed.)
  • Fixed: Two separate reference-counting errors related to ternary operator and Object().
    (#1 was reported by temp01; #2 affected the "base", Object(...) params used to construct obj1 and obj2 in the same example.)
  • Fixed: If a string returned by a scripted object function was assigned directly to a variable, the variable's length was set incorrectly.
    (Caused null characters as reported by ahklerner and temp01.)
  • Fixed: If the last operation in an expression retrieved a string from a temporary object, the object and string were freed prematurely.
    (Caused the "strange characters" in temp01's SplitPath example.)
  • Fixed: Numeric strings with special formatting were not preserved when returned from a function via a variable or passed to a recursive function.
    (Return value bug reported by temp01; also affected vars passed to parameters of recursive functions.)
  • Fixed: If the final result of an expression (other than for Return) is an object, correctly yield an empty string instead of silently aborting the thread.
    (Reported by temp01.)
  • Fixed: __Delete meta-functions sometimes overwrote temporary values in the deref buffer.
    (Reported by infogulch.)
  • Added: An address retrieved via &object may be cast back into an object reference by using Object(address).
    (Described in further detail here.)

Thanks to temp01, infogulch and ahklerner for testing and bug reports. I think I've addressed all of the issues that have been brought to my attention; let me know if I've overlooked something.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 3rd, 2009, 2:06 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
That was fast, thanks for new release Lexikos :)

Here is something I worked out, hope it'll be useful ;)

Btw. why no base function is called when key is removed via object.key:="" :?:

WideObject - Keep track of keys automatically wrote:
WideObject uses non standard variables to keep track of keys in objects.
    "0" - Char 0 contains number of keys in object
    "1" - String digits contain keys. Index is 1 based so you can properly use it in a loop.
Currently you have to use object.Remove(key) to remove a key properly.
    Code:
    object.key:="" ;object["0"] will still keep track of this key.
You can also pass on up to 2 default functions to WideObject:
Code:
object:=WideObject("__CALL","Default_Call","__GET","Default_GET")


Since variables are resolved to number this method should be quite safe :)
Code:
o:=WideObject()
o[SubStr("a1",0)]:="test"
MsgBox % o.1 " . " o[1] " . " o["1"]
string:=SubStr("a1",0)
MsgBox % o[string]


Edit:
Changed object[""] to object["0"], where number of items is saved.


Some examples.

Code:
object:=WideObject()

Loop % (3){
   i:=A_Index
   object[i]:=WideObject()
   Loop 5
      object[i][A_Index]:=Chr(A_Index+64)
}
While object["0"]>=A_Index && i:=A_Index
      Loop % object[i]["0"]
         MsgBox % "Counted Objects: " object["0"]
                  . "`nItems in current object: " object[i]["0"]
                  . "`nItem " A_Index " of object " object[i ""] ": " object[i][A_Index]
ExitApp

Since you can pass on an object address as a parameter to a function, it is also possible to add items inside the function and access these afterwards.
Code:
o:=WideObject()
SetRandom(&o,5)
Loop % o["0"]
   MsgBox % o[A_Index ""] " (Asc: " o[o[A_Index ""]] ")"
o.__Delete()
o:=WideObject()
SetRandom(o,10,64,90)
Loop % o["0"]
   MsgBox % "Only Capital Letters`n" o[A_Index ""] " (Asc: " o[o[A_Index ""]] ")"
ExitApp

SetRandom(ByRef _object,maxcreate=10,minvalue=0,maxvalue=255){
   object:=Object(_object)
   Loop % (maxcreate){
      Random,var,%minvalue%,%maxvalue%
      object[Chr(var)]:=var
   }
}

Function:
Code:
;WideObject for AutoHotkey_L

WideObject(p0="",f0="",p1="",f1=""){
   If (p0 && f0)
      Return (p1 && f1)
      ? Object("base",Object("0",0,"__Set","WideObject_Set","Remove", "WideObject_Remove",p0,f0,p1,f1))
      : Object("base",Object("0",0,"__Set","WideObject_Set","Remove", "WideObject_Remove",p0,f0))
   Return Object("base",Object("0",0,"__Set","WideObject_Set","Remove", "WideObject_Remove"))
}

WideObject_Remove(clr,name){
   clr[name]:=""
   Loop % clr["0"]{
      If (clr[A_Index ""]=name){
         deleted:=A_Index
      } else if (deleted){
         clr[deleted ""]:=clr[A_Index ""]
         deleted++
         if (clr["0"]=A_Index)
            clr["0"]:=clr["0"]-1,clr[A_Index ""]:=""
      }
   }
}

WideObject_Set(clr, name, val){
   static func,varpointer
   If (!func){
      if varpointer := RegisterCallback(A_ThisFunc)
           func := NumGet(varpointer+28),DllCall("GlobalFree","uint",varpointer)
      while varpointer:=NumGet(NumGet(func+20,0,"Uint")+((A_Index-1)*4),0)
         If (DllCall("MulDiv","uint",NumGet(varpointer+24,0),"int",1,"int",1,"str")="name")
            break
   }
   If name<>
      If (NumGet(varpointer+20,0,"Uchar")=1)
         clr["0"]:=clr["0"]+1,clr[clr["0"] ""]:=name
}

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Last edited by HotKeyIt on October 4th, 2009, 2:01 pm, edited 5 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 3rd, 2009, 2:15 pm 
Offline

Joined: July 9th, 2009, 9:25 pm
Posts: 120
Lexikos wrote:
Quote:
Revision 33 - October 3, 2009


NICE!

Btw, Sean reported the following bug in COMo thread:
Sean wrote:
Now I quoted one in the doc, I'll do one more.
Quote:
If a dot appears at the beginning of an expression or is preceded by an operator such as + or *, it is unconditionally treated as a floating-point literal. If a dot is followed by a space, it is treated as the concatenation operator; if in that case it is not preceded by a space, an error is raised. Any other unquoted dot is treated as an object-access operator.
This overlooked one: .=, so error on:
Code:
sKeys.=sKey "`n"


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 3rd, 2009, 5:41 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
I intentionally separated these replies (excluding the last one) from my previous post, then forgot to post them. :lol:

Sean wrote:
__Get/__Set doesn't support parameters?
They do, but they have the usual problem when it comes to detecting how many were passed:
Quote:
Each meta-function can accept only as many individual parameters as it defines; excess parameters are discarded. Since the r-value of a "set" operation is treated as the final parameter, it is the first to be discarded if too many parameters are passed.

Although a varying number of parameters can be handled by declaring some as optional, the actual number of available parameters can be determined only by comparing each parameter to its default value. Consequently, a value must be reserved for this purpose.


Source: AutoHotkey_L - Objects: Meta-Functions (Known limitations)

However, obj.item[n]:=v currently translates into ObjSet(ObjGet(obj,"item"),n,v), which mightn't be intuitive with COM. I intend to make it equivalent to obj["item",n]:=v which translates into ObjSet(obj,"item",n,v). With the default behaviour described under Arrays of Arrays, it'll end up doing the same thing except that obj.item can be automatically initialized.


HotKeyIt wrote:
Why is set function not launched when a key is removed?
As explained in the documentation, __Set is invoked when a new key-value pair is about to be created. It is not invoked if the key-value pair already exists, even if it is being changed or removed. It's loosely based on Lua's __newindex metamethod.
Quote:
Is there another way to do that?
Don't store values in the object directly.
Code:
x := Object("", Object()  ; MUST be set before base.
          , "base", Object("__Set", "x_Set", "__Get", "x_Get"))

x.A := "Apple" ; Sets x[""].A via x_Set.
x.B := "Bravado"
MsgBox % x.A ; Retrieves x[""].A via x_Get.
MsgBox % x.C ; Returns an empty value since x[""].C doesn't exist.
MsgBox % x["","B"] ; Bypasses x_Get.

x_Set(x, n, v)
{
    MsgBox, 0, %A_ThisFunc%, % n "=" v
    ; Store the value in our real storage object and return its result
    ; to indicate that no new key-value pair should be created.
    return x["",n] := v
}

x_Get(x, n)
{
    ; Retrieve the value from our storage object. This should never recurse
    ; because x_Get would only be called if x[""] doesn't exist, and we made
    ; sure to store an object in it before associating this meta-function with x.
    v := x["",n]
    MsgBox, 0, %A_ThisFunc%, % n "=" v
    return v
}
To prevent direct access (i.e. x["","B"]), you may use a private object as a key instead of "".

ahklerner wrote:
how can i make this work?
Here's the documentation for the new feature:
Quote:
To cast an address previously retrieved via address := &object back into a usable object reference, use Object(address). This is an advanced feature which should be used only with caution; see Reference Counting. It may be useful for associating an object with a callback via A_EventInfo.

Source: AutoHotkey_L - Objects: Object()

Quote:
However, taking the address of an object (via address := &object) does not increment its reference count. To ensure the address remains valid when all other references to the object are released, follow this example:
Code:
; Increment the object's reference count to "keep it alive":
DllCall(NumGet(NumGet(address+0)+4), "uint", address)
...
; Decrement the object's reference count to allow it to be freed:
DllCall(NumGet(NumGet(address+0)+8), "uint", address)

Source: AutoHotkey_L - Objects: Reference-Counting

Example (oversimplified--passing by address is entirely unnecessary in this case):
Code:
e := object()
func(&e)
MsgBox % e.text
return

func(ObjAddress) {
    Object(ObjAddress).text := "some text"
}
Be warned that although Object() detects some obvious errors, attempting to use an invalid address (such as the address of an object which has been deleted) will likely crash the script.

infogulch wrote:
ahklerner: I think this would have more to do with a general variable Alias() function than objects specifically, though it might be especially nice for objects.
The problem with passing variables via A_EventInfo is that each callback must have its own, uniquely-named variable. Objects aren't as tightly bound to the script.
Quote:
Alias(newVar, A_EventInfo+0) ; possible syntax for your example
It's been done already; see LowLevel (__getVar and __alias) or AutoHotkey.dll (getVar and alias). Just don't try to hand it an object's address; objects and variables are two very different things.
Quote:
Now that we have objects, a handy function definition sugar would be to allow the last param in the definition be passed as an object that contains all remaining params from the caller.
I plan to implement that functionality, but not necessarily with new syntax.
Quote:
It would be especially handy for the object __call meta function, since it handles an arbitrary number of params
__Get and __Set also accept multiple parameters, but since there isn't yet any clean way to handle it in script, none of my examples have shown it. Part of the problem is that there's no easy way to pass a variable number of parameters to a function, as your Default_Call example demonstrates.
Quote:
A somewhat similar idea, perhaps the "opposite" of the above, is to dynamically turn an object into multiple params.
Although I'm not in favour of overloading "*", I appreciate your suggestion.

HotkeyIt wrote:
Since you can pass on an object address as a parameter to a function,
I think you're missing something; specifically, that objects can be passed by reference, by simply removing &. Please note,
Quote:
This is an advanced feature which should be used only with caution

HotkeyIt wrote:
o.__Delete()
__Delete() should not be called explicitly unless you want it called twice. In that particular case it doesn't appear to exist anyway.
Quote:
Return Object("base",Object(...))
I would recommend creating a single base object and using it for each WideObject. COMo shows how simple it is. Creating a new base object for each new object more or less defeats the main point of that feature.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 4th, 2009, 5:48 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
very nice thanks

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 4th, 2009, 4:17 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Lexikos wrote:
HotKeyIt wrote:
Is there another way to do that?
Don't store values in the object directly.

Thats exactly what I was looking for, thank you so much :)

It looks to work perfectly now :D

WideObject()

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2009, 8:14 am 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Hi Lexikos,

It looks like though object[1] contains an integer, object[object.1] resolves object.1 to a string.

In this example when a[a.3] or a[a["2"]] is launching Get function, name should have attrib 16 because a.3 as well as a["2"] contain an integer.

Because of this it is currently not possible to find the difference inside Get function :?

Can you have a look please?
Code:
object:=Object("__GET","GET")
a:=object("base",object)
a[1] a["1"] ;here everything is alright as you can see Attrib for 1 = 16 and "1" = 0
a["2"]:=1
MsgBox % "Set ""2"" := " a["2"]
a[a["2"]] a[a["2"]+0] ;here first reports Attrib 0 instead of 16, second works because of +0
a.3:=1
MsgBox % "Set 3 := " a[3]
a[a[3]] a[a.3] ;here again both reports Attrib 0 instead of 16
Return

Get(clr,name){
   static func,varpointer
   If (!func){
      if varpointer := RegisterCallback(A_ThisFunc)
           func := NumGet(varpointer+28),DllCall("GlobalFree","uint",varpointer)
      while varpointer:=NumGet(NumGet(func+20,0,"Uint")+((A_Index-1)*4),0)
         If (DllCall("MulDiv","uint",NumGet(varpointer+24,0),"int",1,"int",1,"str")="name")
            break
   }
   If name is digit
      is=yes
   Else   
      is=no
   MsgBox % "GET`n`nname: " name "`nis digit: " is "`nVariable Attrib: " NumGet(varpointer+21,0,"Uchar")
}

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2009, 8:34 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
HotKeyIt wrote:
a.3 as well as a["2"] contain an integer
You are mistaken. Numeric literals are stored as strings to preserve formatting; for instance, 0x1 vs 1 vs 0001.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 1036 posts ]  Go to page Previous  1 ... 12, 13, 14, 15, 16, 17, 18 ... 70  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group