AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

OOP or how to create the equivalent
Goto page Previous  1, 2
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
Lexikos



Joined: 17 Oct 2006
Posts: 2739
Location: Australia, Qld

PostPosted: Fri Feb 01, 2008 12:02 am    Post subject: Reply with quote

RaptoR wrote:
...and I get the same "corrupting problem" again (loc disappears after exiting from the function).
How is Set_set_locs implemented? If you are storing everything in variables, there is only one way for it to work:
  • this and loc are passed ByRef to Set_set_locs.
  • If this does not already have space in it for loc, it must be expanded. This involves copying the current contents to a temporary variable, calling VarSetCapacity, and copying the contents back to this.
  • The contents of loc are copied into this.
Quote:
I consider GlobalAlloc as the last way to try, because it has obvious disadvantage - need to free memory manually.
First, variables are never deleted (making a distinction between variables and the contents of variables.) Second, if the initial memory allocated to a variable is less than 64 bytes, AutoHotkey uses a method which avoids the overhead of dynamic memory, but prevents the memory from being freed before the script exits.

With this method...
Code:
Bug_new(x) ; constructor
{
   global ; all vars except x and obj are global.
   static obj := 0
   obj++
   VarSetCapacity(this%obj%, (MAXS + 1) * 4, 0)
   NumPut(x, this%obj%)
   return &this%obj%
}
...the "object" is not freed until you explicitly free it:
Code:
VarSetCapacity(this%obj%, 0)
Additionally, the variable this%obj% is never deleted. Each variable consumes at least 21 + StrLen(name) bytes, plus the size of the initial memory (+1 for null-terminator) if less than 64 bytes.
Back to top
View user's profile Send private message
RaptoR



Joined: 27 Jun 2007
Posts: 22
Location: Earth, Cambrian period

PostPosted: Fri Feb 01, 2008 5:04 am    Post subject: The AHK object system, ver 1.0 Reply with quote

Aha, I finally have found some solution!

We need to use one basic function, Object_new(size) that allocates memory and returns integer numerically equal to the pointer to the memory. In this very first version I'm using global array to prevent object be disposed too early. Maybe in a future version I will be able to implement something like refcounter or even garbage collector Very Happy

Classes are encoded as number of functions that accept "this" (except constructor) and have names like "Class_method". Each field is supported by two synthethic functions "Class$field" (getter) and "Class$$field" (setter). Because of overloading absence in AHK I have to add suffixes to resolve name conflicts (in the example below look at "add*" funtions).

The example is below (prototype java code in comments):
Code:

;; Log() function are here, it just outputs parameter in
#Include lib/log.ahk
;; ultimate allocating function
Object_new(size)
{
   global
   static objc := 0
   objc++
   VarSetCapacity(_this_%objc%, size, 0)
   return &_this_%objc%
}

MAXS := 5
MAXL := 10

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; code below was in the "main" method
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;Set mc = new Set();
;;System.out.println(mc);
mc := Set_new()
Log(Set_toString(mc))

;;Pair p;
;;p = new Pair(); // random
;;mc.add(p.a, p.b);
;;System.out.println(mc);
p := Pair_new0()
Set_add2(mc, Pair$a(p), Pair$b(p))
Log(Set_toString(mc))

;;p = new Pair(); // random
;;mc.add(p.a, p.b, 1);
;;System.out.println(mc);
p := Pair_new0()
Set_add3(mc, Pair$a(p), Pair$b(p), 1)
Log(Set_toString(mc))

;;mc.combine(1);
;;System.out.println(mc);
Set_combine(mc, 1)
Log(Set_toString(mc))

;;mc.combine(2);
;;System.out.println(mc);
Set_combine(mc, 2)
Log(Set_toString(mc))

;;mc.combine(3);
;;System.out.println(mc);
Set_combine(mc, 3)
Log(Set_toString(mc))

;;mc.do_switch(1);
;;System.out.println(mc);
Set_doSwitch(mc, 1)
Log(Set_toString(mc))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; class Set
;;   Loc [] locs = new Loc[Set.MAXS];
;;   int size;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; constructor
Set_new()
{
    global MAXS
   this := Object_new((MAXS + 1) * 4)
   loop % MAXS
   {
      loc := Loc_new(a_index * 10, a_index)
      Set$$locs(this, a_index-1, loc)
   }
   Set$$size(this, MAXS)  ; debug only
   return this
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; synthethic methods for fields
Set$locs(this, index) ;; index = 0..(MAXS-1)
{
   return NumGet(this+0, index * 4)
}
Set$size(this)
{
   global MAXS
   return NumGet(this+0, MAXS * 4)
}
Set$$locs(this, index, value) ;; index = 0..(MAXS-1)
{
   NumPut(value, this+0, index * 4)
}
Set$$size(this, size)
{
   global MAXS
   NumPut(size, this+0, MAXS * 4)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void add(int x, int y)
;   {
;      size = Math.min(size + 1, MAXL);
;      shiftr(size - 1);
;      locs[0] = new Loc(x, y);
;   }
Set_add2(this, x, y)
{
    global MAXS
   size := Set$size(this)
   Log("size"size)

   Set$$size(this, (MAXS < size + 1 ? MAXS : size + 1))
   Set_shiftr(this, size - 1)
   loc := Loc_new(x, y)
   Set$$locs(this, 0, loc)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void add(int x, int y, int n)
;   {
;      add(x, y);
;      locs[0].set(n);
;   }
Set_add3(this, x, y, n)
{
   ;;add(x, y);
   ;;locs[0].set(n);
   Set_add2(this, x, y)
   loc := Set$locs(this, 0)
   Loc_set(loc, n)
   ;;Set$$locs(this, 0, loc)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void combine(int n)
;   {
;      if (size == 0)
;      {
;         Pair p = random();
;         add(p.a, p.b, n);
;         return;
;      }
;      for (int i = 0; i < size; i++)
;         locs[i].unset(n);
;      locs[0].set(n);
;   }
Set_combine(this, n)
{
   ;; if size == 0, do nothing
   ;if (size == 0) return
   ;for (int i = 0; i < size; i++)
   ;   locs[i].unset(n);
   ;locs[0].set(n);
   size := Set$size(this)
   if (size == 0)
      return

   loop % size
   {
      loc := Set$locs(this, a_index - 1)
      Loc_unset(loc, n)
   }
   loc := Set$locs(this, 0)
   Loc_set(loc, n)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void do_switch(int index)
;   {
;      Loc l = locs[index];
;      shiftr(index);
;      locs[0] = l;
;   }
Set_doSwitch(this, index) ; index = 0..(MAXS-1)
{
   loc := Set$locs(this, index)
   Set_shiftr(this, index)
   Set$$locs(this, 0, loc)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void shiftr(int k)
;   {
;      for (int i = k; i > 0; --i )
;         locs[i] = locs[i - 1];
;   }
Set_shiftr(this, k)
{
   ;for (int i = k; i > 0; --i )
   ;   locs[i] = locs[i - 1];
   loop % k
   {
      i := k + 1 - a_index
      loc := Set$locs(this, i - 1)
      Set$$locs(this, i, loc)
   }
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public String toString()
;   {
;      String str = "{[" + size + "]\n";
;      for(int i = 0; i < size; i++)
;         str += (locs[i].toString() + "\n");
;      str += "}";
;      return str;
;   }
Set_toString(this)
{
   size := Set$size(this)
   str := "{[" . size . "]`n"
   loop % size
   {
      i := a_index - 1
      loc := Set$locs(this, i)
      str .= Loc_toString(loc) . "`n"
   }
   str .= "}"
   return str
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; class Loc
;;   boolean [] groups = new boolean[Set.MAXL];
;;   int x, y;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public Loc(int x, int y)
;   {
;      this.x = x;
;      this.y = y;
;   }
Loc_new(x, y)
{
   global MAXL
   this := Object_new((MAXL + 2) * 4)
   Loc$$x(this, x)
   Loc$$y(this, y)
   return this
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; synthethic methods for fields
Loc$groups(this, i)
{
   return NumGet(this+0, i * 4)
}
Loc$x(this)
{
      global MAXL
   return NumGet(this+0, MAXL * 4)
}
Loc$y(this)
{
   global MAXL
   return NumGet(this+0, (MAXL + 1) * 4)
}
Loc$$groups(this, i, v)
{
   NumPut(v, this+0, i * 4)
}
Loc$$x(this, v)
{
   global MAXL
   NumPut(v, this+0, MAXL * 4)           
}
Loc$$y(this, v)
{
   global MAXL
   NumPut(v, this+0, (MAXL + 1) * 4)
}
;; end of synthethic methods
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void set(int n) { groups[n] = true; }
Loc_set(this, n)
{
   Loc$$groups(this, n, 1)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public void unset(int n) { groups[n] = false; }
Loc_unset(this, n)
{
   Loc$$groups(this, n, 0)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public boolean get(int n) { return groups[n]; }
Loc_get(this, n)
{
   return Loc$groups(this, n)
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   public String toString()
;   {
;      String str = "{(" + x + ", " + y + ") ";
;      for (int i = 0; i < Loc.MAXL; i++)
;         str += i;
;      str += "}";
;      return str;
;   }
Loc_toString(this)
{
   global MAXL
   x := Loc$x(this)
   y := Loc$y(this)
   str := "{" . x . "," . y . ","
   loop % MAXL
   {
      i := a_index - 1
      str .= Loc_get(this, i)
   }
   str .= "}"
   return str
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; class Pair
;;    int a, b;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Pair_new0()
{
   this := Object_new(8)
   Random a, 100, 200
   Random b, 100, 200
   Log("a" a " b" b)

   Pair$$a(this, a)
   Pair$$b(this, b)
   return this
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   Pair(int a, int b)
;   {
;      this.a = a;
;      this.b = b;
;   }
Pair_new2(a, b)
{
   this := Object_new(8)
   Pair$$a(this, a)
   Pair$$b(this, b)
   return this
}
Pair$a(this)
{
   return NumGet(this+0, 0)
}
Pair$b(this)
{
   return NumGet(this+0, 4)
}
Pair$$a(this, a)
{
   NumPut(a, this+0, 0)
}
Pair$$b(this, b)
{
   NumPut(b, this+0, 4)
}


The code works like charm, but there is something to do yet:
1. vtable
2. exceptions
3. smarter memory management

Despite these issues, I hope you enjoyed it Smile
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2739
Location: Australia, Qld

PostPosted: Fri Feb 01, 2008 9:17 am    Post subject: Re: The AHK object system, ver 1.0 Reply with quote

RaptoR wrote:
Maybe in a future version I will be able to implement something like refcounter or even garbage collector
As I pointed out already, variables can not be deleted.

I don't understand your aversion to GlobalAlloc. The problems I see with your current method are:
  • _this_%..% can never be deleted.
  • No "object" (the contents of _this_%..%) can ever be deleted, since you need to know the var's name, not just its address.
  • No "object" is ever deleted before the script exits, so it is the equivalent of using GlobalAlloc but never explicitly freeing the memory. In other words, GlobalAlloc's "obvious disadvantage" as you put it, does not exist.
If you did implement a "refcounter or garbage collector", you would need to explicitly add and release references. GlobalFree would simply be called when the last reference is "released".

Consider using this:
Code:
Object_new(size) {
   return DllCall("GlobalAlloc","uint",0x40,"uint",size)
}
Object_delete(ptr) {
    DllCall("GlobalFree","uint",ptr)
}
Back to top
View user's profile Send private message
RaptoR



Joined: 27 Jun 2007
Posts: 22
Location: Earth, Cambrian period

PostPosted: Mon Feb 04, 2008 10:38 am    Post subject: Re: The AHK object system, ver 1.0 Reply with quote

lexiKos, thank you for the replies, I appreciate your help!

lexiKos wrote:

I don't understand your aversion to GlobalAlloc. The problems I see with your current method are:
  • _this_%..% can never be deleted.
  • No "object" (the contents of _this_%..%) can ever be deleted, since you need to know the var's name, not just its address.
  • No "object" is ever deleted before the script exits, so it is the equivalent of using GlobalAlloc but never explicitly freeing the memory. In other words, GlobalAlloc's "obvious disadvantage" as you put it, does not exist.


Embarassed I thought that memory allocated with GlobalAlloc would not automatically freed when the application exited. But actually windows will free all resources (not memory only, but also GDI handles, etc.) when a process exits - even if the process fails to do so on its own. So, yes, in general, there is no difference between AHK global variables and memory given by GlobalAlloc.

Quote:

If you did implement a "refcounter or garbage collector", you would need to explicitly add and release references. GlobalFree would simply be called when the last reference is "released".

Yes, you are right. Now I'm thinking to move from inventing a bicycle Smile towards using scripts with AHK (like Scheme, Javascript, Python etc).
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group