AutoHotkey Community

It is currently May 26th, 2012, 4:59 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 259 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 18  Next
Author Message
 Post subject:
PostPosted: February 21st, 2009, 10:37 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
bmcclure wrote:
Is there a better way to do this? I'm not sure if conflicts and dependencies will be freed properly if I delete the Mod object, as I'm assuming I'll have to loop through each Vector object and delete its sub-objects?

Bzzzt, wrong! Since they are Vectors, you should use type "obj" to set and get them. The "get value" will be the address, which can be passed to functions that use the Vector. The set function, automatically destroys the old object, and increases the lock count for the new object (if it's not NULL - 0). In other words, THEY WILL BE DELETED AUTOMATICALLY - just remember in you Mod_destroy function to call the set function and pass 0 like you do to clear the other values ("" for Strings).

Come on, they are objects - self contained time bombs waiting to be destroyed :D. And when you destroy the Vector, it destroys all within it, and if the Vector contains objects, it destroys them - aren't dynamic functions great!

Forgot to mention, like all objects, it will only actually be destroyed if the lock count is 1 (or 0). Meaning, if two objects both use the same Vector, and you destroy the first object, the Vector remains (to be used by the second object). Then, when deleting the second object (assuming another object isn't using the Vector), it will be destroyed.

That's the power of lock count, combined with this function call in the destroy function.

Code:
if !Class_readyToDelete(ModObject)
      return false


Edit:
Just remember that once the object is destroyed, you can't refer to it again. I'm going to add a modification to the code that returns the lock count when setting a value, which can be then used to see if the object still exists. The function will return true, like it does now, if the object was actually destroyed, and a negative number (representing the lock count), if the object still exits. You can then test for the return and if it's less than 0, the object still remains. It will still be "true" in a boolean, so you can still use it to test if the function was successful. False is still returned if the object is copied to itself, and True is retured if the object is destroyed (for good).

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Last edited by animeaime on February 21st, 2009, 10:48 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 10:45 pm 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
Wow, thanks a lot for that explanation! I'm liking these libs more and more all the time :)

Another question, about the Classname_destroy_private function

For example, in the Rectangle class. It calls Rectangle_destroy_private, but since the class contains no such function, the file fails to load by itself since it's considered a missing function.

This means it's required for the user to create a destroy_private function in their script, even if they don't have private values to store, right? (maybe rectangle is a bad example)

What about the possibility of turning the call into a dynamic function call, so that AHK simply returns nothing if the function doesn't exist?

Maybe like:
Code:
func := "Rectangle_destroy_private"
%Func%(RectangleObject)


I don't know what the implications of this are, or if it affects performance in any significant way, but it might be easier to incorporate various classes into your scripts if you don't always have to create a destroy_private function even if no privates have been defined.

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Last edited by bmcclure on February 21st, 2009, 10:57 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 10:54 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
No problem, I'm going to work on those two updates right now - be up in a bit.

1) Adding the ability to get/set individual bits - will work the same as normal bit flags. The first bit flag will return 2^0 = 1, the second 2^1 = 2, the third 2^2 = 4 (if the bit is set) and 0 if unset (for all).

2) The new lock count (as a negative) will be returned when setting object types. For example, a return of -1, means the object exists still in 1 place, a return of -2 means 2 places, etc. This value can be used to see if the object was actually destroyed or only if its lock count was decreased. The return will be +1 if the object is actually destroyed. This still allows using the return as a quasi-boolean to see if the operation was successful. Zero will still be returned if the object set is the object already there (i.e. trying to replace the object with itself), and the empty string is returned to indicate an error.

I'll have those updates done in a bit. Still working on the site - modifying GenDocs to make it easier for me to develop and maintain the site.

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Last edited by animeaime on February 21st, 2009, 10:57 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 10:56 pm 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
See my new question above, just in case you missed it since you responded before I finished editing that post :)

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 11:16 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
If your Class isn't designed to allow User-Defined values, you can comment out the call (and thus it won't go looking for the function). This allows not needing the function call if your Class doesn't allow user-defined values. So the simple question is, do you plan to allow the user to add values to your object (non-built in values)? If so, they can associate extra members - Objects, Strings, basic types with you object, which are freed in the destroy_private function (created by the user). If you don't intend to allow user-defined values, then you can comment out the call to destroy_private in your destroyed, remove UserDefinedSize as a parameter in your new function, and create a static variable UserDefinedSize = 0 in the new function.


Now, the reasoning:

If the Class allows user-defined values, the function IS required, since the user may set values. Since these values can be Objects, Strings, or normal data types, it is necessary to delete them specifically. A String's deletion is done differently than an Objects, for example - even though they are stored, internally, as uints (memory addresses). The purpose of the destroy_private function is to destroy these user-defined values (that are not known when the function is created - that's the purpose of the tyye parameter (to give the object a type - but the type is not associated with the member). For example, my Menu wrapper allows associating values with a menu / menu item. Right now, there may be many (or few) people using that library. Each user can have their own values, for each script, because the Menu_destroy_private and MenuItem_destroy_private function cleans up those values.

I could use a dynamic call, and if the function didn't exist, the code would continue. However, the memory (if any) for any user-defined values wouldn't be freed - creating memory leaks.

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 11:28 pm 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
I do understand that it's required only if you want user-defined values. But what if you want to give the option of user-defined values without making it a requirement?

For instance I would like to allow my Mod class to be extended by other libraries (in very loose terms). I have no way of knowing at this point if those extensions will require extra values or not.

It's no big deal requiring them all to have a destroy_private function, but was just curious as to the possibility of making it optional.

I tested it in my Mod class, and it seems to work fine--barring any performance hit I may notice later when it's doing a lot of work :)

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2009, 11:53 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
It's risky - I guess that's my worry. I understand that if you don't use any user-defined values, then the code will notice no loss. My worry is that some "idiot" will try to set user-defined values, but forget to clear them. Maybe I shouldn't worry about that "idiot"?


Here are my thoughts:

The reason I used this method:

On one side, I want it included to make sure it's defined. My worry is that users may think that they can define user-defined values WITHOUT supplying a destroy_private function to destroy them. That's why I thought making the call explicit - it also provides a runtime check that you have a destroy function for all used Classes (that allow user-defined functions). This means that the script will not run unless such functions are defined - allowing the function to be dynamic removes that check. Somebody might inadvertenly use the library, think they can use user-defined values without destroying them, and create bad code. I guess I don't want that on my shoulder.

Also, in true OOP style, you would put all the destroy_private functions in an external ahk file and have an include statement for it. Thus, you would have an ahk file that contained the necessary destroy calls. The user of the Class would then modify them if they use any user-defined values. If not, the function is there and so the code doesn't complain. This is the method I used in my menu wrapper with the MenuLibraryTemplate.ahk file (check out how I did it)


Now, the argument for:

I'm not sure what performance difference it will make using dynamic functions. The code uses them to destroy the objects in a Vector (and other container Classes), and I didn't notice anything to write home about.

The call would be optional (i.e. dynammic). If the function exists, it will call it, else it will continue. This would allow users that don't make use of user-defined values to not have to worry about a destroy_private function.


In short, I guess I see making it optional as the "lazy programmer" strategy. My suggestion would be to create empty destroy_private functions for all your classes, put them in an external ahk file, have an include statement to include that file. This way, your users can modify that file to destroy any user-defined values they create, or they can leave it alone if they don't use any user-defined values.


So, my verdict. I'm keeping the old style. Just put the necessary functions in separate ahk file, and have an include statement for it. This way, the users of the Class can easily free their values by modifying the one ahk file. Also, it ensures that the destroy_private functions are part of the Class.


Now, a question, why is it that you want it to be optional? Although I gave my reasoning, if there is a certain need that my solution doesn't address, I'll gladly change my view.

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 12:43 am 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
Mainly to be lazy, as you said.

The main reason I'd prefer to have an optional call instead of an explicitely-defined (but empty by default) call in an external file is for coding simplicity.

If I have private values specified in a file somewhere, that's the file I want to destroy them in, personally. I'd prefer not to have to open another file and put the values there as well, especially when using the class as a library function since the user doesn't want to keep the external include file in their project if it's handled by a lib. So that brings the issue of, if you create the destroy_private function in your script, and it also exists in the included external file, you'll have a duplicate function.

One way I can think of around this, which I think conforms to stricter OOP standards (than what I proposed before, at least), as well as offering flexibility would be if I:
1. create an external file with a destroy function, as you suggest. in the case of "extensions" to classes, this is where the extension could clear its private values as well.
2. put a dynamic function call in the destroy_private function, calling a destroy_user function (if it exists), which can be placed in the end-user's script, or wherever.


Another question, for laziness sake:
Is it possible for Class to keep track of the values (and types) defined, both built-in and user-defined, and free them automatically?

Since it's always the same method to free a particular type of object, it seems the call could be automated. And since the Class library is used to store all values in a class ultimately, I think it would have the capacity to keep a vector (or some other object type) of values for each class, and (optionally?) automatically free them when destroyed.

Or am I way off base there? I know it's more of a convenience thing than actual added functionality, but it would free up a lot of back-and-forth function editing when adding or removing values.

Come to think of it, it would probably add a lot of additional overhead to the Class library. Perhaps it would still be nice as an optional function, however... although maybe more trouble than its worth.

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 2:35 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
Let me ask what the benefit is, because it is a big overhead, and not backward-compatable? Also, let me correct my previous mistake. The user would include the file with the destroy_private functions into their project, not you into yours.

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 3:43 am 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
Eh, it's not important; The main benefit would be decreased coding time and class-fussing due to automation. In realistic terms, the benefit would be not having to create class or end-user functions for cleaning things up, while still having them managed.

I do see the downside of the additional overhead, and it's definitely not for everyone. My idea would be to have it perhaps be a boolean parameter when creating the object instance whether or not to track/clean values automatically for that object.

I realize it's probably not worth implementing functionality like this right now, but just thought it would be nice as I was tweaking my Class file quite a bit as I changed values earlier.

Then again, I'm spoiled; I spend 1/2 my development time in a PHP framework that handles most of the menial tasks itself :)

You're probably right, for most applications the downsides may outweigh the benefits.

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 4:12 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
I'm going to turn down the feature. It would require inputting the types (instead of setting the size) - for user-defined values. Either way, it means the same work for the user. Also, if I added it, it would be sooner, not later, as it wouldn't be backward-compatable. So, I'm going on the record and saying that I won't add the feature. I believe the benefit outways the harm - due to both overhead and overall "weirdness". The analogy that pops in my head is that I'm used to closing a cupboard after I open it, which is how I designed this library. Making the delete automatic, would mean, 1) I have to tell the cupboard how to close itself, then it would automatically close for me. Sorry, but that's just outside of my thought of OOP (or reality). Why not just close the cupboard yourself?

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 4:54 am 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
To answer your question:
1. Usually I open and close one cupboard (or a small number of cupboards) at a time; no problem. I don't program that way, however. Closing 30 cupboards is more tedious than closing 1. And it goes up from there.
2. Because when cupboards have the ability to close themselves, I won't have to :)

No big deal, though; it's something that I could easily add as a separate wrapper if it turns out that it truly would save me development time in the longrun.

I'm starting to think many of the features I'd really like to see would be better handled by a custom wrapper that utilizes the Class library and adds higher-level functionality.

Back to coding...

ps. And you're right, I'm not disputing that it makes logical sense to close what you open. But rather implying that automating it doesn't change the fact that it happens. Your cupboard closes because you close it. Mine closes because the motion detector senses I've left the kitchen and kicks a little motor that closes the cupboards and wipes down the counters :) (I wish, but either way, our cupboards get closed)

pps. I don't mean to come off strongly, or imply that I think you should implement all of my suggestions, just throwing ideas out there to get some feedback and maybe spark some additional feature suggestions.

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 22nd, 2009, 5:37 pm 
Offline

Joined: November 24th, 2007, 9:07 pm
Posts: 774
Quote:
I'm adding some much needed functionality to Cddl and Array and will add the like to Vector, so that should help if you require "search" features. The question becomes, how does your data need to be stored?


Is anything like this still being implemented (or available and I just didn't notice)? I'm not sue how the search functionality will do its business, but currently when I need to find a value, I'm looping through the list or array one item at a time, getting the value, and checking if it matches the search. I'm hoping there may be a more efficient way, though.


Also, rehashing one older question for a new topic. I used Cdlls as a basis for creating my ModList class. A ModList is a precisely ordered list of Mod objects (used to store a load order in this case). I chose a Cdll because I'd like to allow users to move items around in the list without a lot of overhead, and was previously under the impression that it was a lot less costly to move things around in a Cdll than in a Vector.

However, after re-reading one of your responses on the first page, I'm not so sure anymore, since Cdlls use more memory, especially for larger lists. My main question becomes, have you figured out how the overhead of the larger memory usage of the Cdll compares to the overhead of the Vector having to move things around in memory?

I'm having trouble deciding if I've gone the right way by basing ModLists off of Cdlls instead of Vectors. I would prefer the 'indexed' nature of a Vector, since the index would in effect be my load order. But I like how easy it is to handle adding and moving things in a Cdll without it having to shift them around in memory.

Starting to think, that if I used a vector, I could probably just wrap the Vector class with the ModList class and save a lot of code by using user-defined values instead of building my own container class just to have specific built-ins. Still trying to wrap my head around what will work better; I'm anxious to get ModLists working, but I don't want to realize down the road that I should have used a fundamentally different approach.

Thanks for your insight :)

_________________
Ben

My Trac projects
My Wiki
[Broken] - My music


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 23rd, 2009, 2:14 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
@bmcclure: No, you don't come off too strongly, and please don't back down either. My feelings may be hurt, but that shows that I care about this library. Also, I do feed off yals suggestions, and with them, this library can become even better.

@bmcclure: I ran a test of inserting an object into the first position of a Vector 1000 times (which means that the all the objects must be moved down, each time). Also, I didn't set the initial capacity, so it had to reallocate seven times (10 * 2^7 = 1280). The first 10 is the default initial capacity. The default behavior is to double each time.

Here is my test code.
Each takes about 1/2 second, on my computer, at Count = 1000. The results I got suggest that initializing the Vector to the correct size takes longer. Also, Cdll takes even longer than that. This really suprises me - checking to see if it's a design flaw.

Code:
;number of objects to add
Count := 1000

/*
Vector (no initial size set)
*/

;don't set initial size
myVector := Vector_new()

start := A_TickCount

Loop, %Count%
{
    ;automatically resizes as needed
    Vector_add(myVector, 1, String_new(A_Index))
}

;total time
VectorNoInit := A_TickCount - start

;free memory
Vector_destroy(myVector)


/*
Vector (initial size set)
*/

;set initial size
myVector := Vector_new(Count)

start := A_TickCount

Loop, %Count%
{
    Vector_add(myVector, 1, String_new(A_Index))
}

VectorInit := A_TickCount - start

;free memory
Vector_destroy(myVector)

/*
Cdll
*/

myCdll := Cdll_new()

start := A_TickCount

Loop, %Count%
{
    ;add before (last position)
    ;inserts don't move memory around
    Cdll_addBefore(myCdll, String_new(A_Index))
}

CdllTime := A_TickCount - start

MsgBox, % "Vector (no init): " . VectorNoInit
    . "`nVector (init): " . VectorInit
    . "`nCdll: " . CdllTime



Some planned changes:
I'm going to add "index wrapping" for all functions that use indexes. So, 0 can be used to instead of Vector_size(), -1 for Vector_size() - 1, etc. I'll add the same ability to Array, which uses Array_length() to return the "size".

Also, going to document, if I haven't that Vector_add(VectorObject, object) can be called to add to the end of a Vector.


Seach features:
There's nothing in development for search features, but I think I know how I want to do it, so I'll start. I haven't heard any feedback and so didn't want to add it yet. Now that I heard there is a need, I'll add it how I thought. A identical search functions will be added to each of Array, Cdll, and Vector Classes.

Below are my thoughts, feedback welcome.

Syntax:
Code:
Vector_indexOf(VectorObject, value, index = 1, useFunction = "getValue")


Indexes will "wrap", entering -1 will start at Vector_size() - 1, -2 will start at Vector_size() - 2, etc.


The function will search through VectorObject and call the specified function on each object in the Vector (starting at the specified index).
Then, the return of the function will be compared to specified value - the index for the first matching object will be returned.
Note: by using different functions, you can use the same search function to look for different values. Also, the function can be ANY function in the Class. Ex. you could compare Rectangle objects by area (via Rectangle_getArea - function = "getArea"). Likewise, user-added functions, provided they use the standard naming, will be usable as well. Ex. you can search a Rectangle by color (via Rectangle_getColor - function = "getColor").

Should I add a final parameter, <includedClasses> to search only objects of the specified Class? The default value would be "" - meaning all objects will be compared.

Edit:
I forgot to mention that the called function MUST have the following syntax:
Code:
%ClassName%_%useFunction%(ClassObject)


Example:
If you have a Vector of Student objects, you might have a getName function and a getStudentID function.

To search for a student ("animeaime") by name, you would call:

Code:
Vector_indexOf(VectorObject, "animeaime", 1, "getName")

This would, for each object in the Vector, call its getName function.

Ex.
if Vector[1] is a String object, it would call String_getName (which doesn't exist), so it wouldn't be a match and continue. It would then move to Vector[2]. Let's say that is a Student object whose getName function returns "animeaime" (hey, that's me). Then, the return would be 2. If there is no match, zero is returned. Therefore, you can use this as a quasi-boolean to see if the object is in the list.

Code:
if Vector_indexOf(VectorObject, "animeaime", 1, "getName")
{
    MsgBox, % "animeaime is in VectorObject."
}


I'll also add the getAddress function to Cdll. For Cdll, since it lacks "indexes", I think it would be best to return the address. Well, actually, it does have indexes, so I could return an index. Also, I'll add a get/set function (that work on index). However, such get/set methods would be O(n) - linear time versus O(1) - constant time (for Array and Vector).


There will also be a findMatch function which mimics indexOf, but returns the address for the matching object (instead of the index) - looking for suggestions for function name.


Also, any other functionality can be added, so keep the ideas coming. I'm going to take a little break from working on my libraries (after I add search). I need to get back to my project, I want to start implementing all these features in my own programs.

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 23rd, 2009, 5:30 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
@bmcclure: I just thought of this. I remember that in your Mod_new you do a check if the item != "". If you are storing Strings such a call is not needed, unless you are using it to prevent a function call, then never mind. When setting a String type, and the string is blank, the setString/setValue function doesn't store a blank string (i.e. no memory is used).

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 259 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 18  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google Feedfetcher, IsNull and 3 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