Hey all, In follow-up to a post i did eons ago about Objects in MASM32, I have built a little tool (50Kb) that will generate 'classes' in .asm code. I decided to do the tool before the writing a tutorial such that people may get a better hands-on to the concept, rather than hear me bable about it (which might get messy). I still plan to write a tutorial, based around my class object creator tool with some basic applications. But if you have a rough idea of how objects work ie) constructors/destructors, and instances of the class you should be able to get going ok! I have provided Objects.inc as well to help use the class files. Things to note: I have provided very minimal error checking. If you use only the buttons you will have no problem compiling, but if you 'tweek' a proto type or something make sure it right. As well its the users job to ensure method/variable names have no spaces and dont start with numerics etc. etc. I didnt want to waste all my time coding checking for such things :) Anywho, please check it out and lemme know what you like/dont like about it. You can find it on my web site: NaN's Web Site Hope you like NaN
BTW: Just to let you know now, this is not a complete object tool set. Inheritance has not been figured out yet, so for now, the classes are unique to themselves. You can however generate multiple instances of that same class.
This should also give you a good idea how to use it as well :D Enjoy NaN
ie] NEWOBJECT name1, ACLASS NEWOBJECT name2, ACLASS METHOD name1, ACLASS, setValue, 100 METHOD name2, ACLASS, setValue, 5 METHOD name1, ACLASS, getValue eax == 100 METHOD name2, ACLASS, getValue eax == 5 DESTROY name1, ACLASS DESTROY name2, ACLASS
Nice! This is one of the things I have been looking for!
Pretty cool. I just took a quick peek at the tool, made a simple class and looked over the generated code. I didn't try to compile it or heaven's forbid, run it, but it seems like a solid shell for class creation. Of course, I saw several things personally I'd tweek. Things like get the mention of 'coinvoke' out of objects.inc (call it something else here, like METHOD, yeah?). And capatilization of the Get and Set methods, perhaps a few others. One one thing I couldn't see is how the constructor and destructor methods get run. Do you intent these to be called 'manually"? I'm sure some way to run them automatically could be arranged, perhaps put the method pointers into the class structure, then have NEWOBJECT and DESTROY macros call them. While working on my "IDE" (on hold while I'm preparing to move the end of the summer and need to prepare 1 house and move out of 2 apartments) I did some useful stuff for "containment." Basically, when I define a class I do it in a seperate .asm file, and what needs be public for the main.asm file is bundled into an .inc file. Perhaps you should concider a similar division of code for the same reason: containment. The biggest drawback to such a multi-file scheme is Quick Editor will no longer be an appropiate editor as it's a single doc editor. A multiple doc editor is best for this. I found TextPad acceptable, no doubt there are others. Also, build and link settings get complex, but do follow a simple pattern. I gave in and made custom .bat files to build (cause I'm too stupid to use make.exe). Main point it, your tool should work as is. Good job. Cool stuff. This message was edited by Ernie, on 5/21/2001 7:42:13 AM
Ernie, I will certainly corret the include! ~~ Sorry for my ignorance! I made mention to you on my site, but forgot to do the same on the METHOD macro (Its where this entire idea started rolling ~ after studying your coinvoke Macro). Heck even the stucture itself is basically you design! (with a few tweeks :) ~~ Again Sorry if this bothered you. :( ) Ya, the other two macros do just that, call the constuctor and destructor on creation and destruction.
Part 1): builds an invoke: "invoke CLASSNAME_Init, eax, args" Part 2): if the variable is not defined (and shouldnt be) it will add the code:
NEWOBJECT MACRO pName:REQ, ObjType:REQ, args:VARARG 1)-> LOCAL instring instring CATSTR
,<&ObjType>,<_Init, eax> IFNB instring CATSTR instring, <, >, <&args> ENDIF 2)-> ifndef &pName .data? &pName&Data typedef ptr ObjType pName &pName&Data ? .code endif 3)-> invoke GetProcessHeap invoke HeapAlloc, eax, NULL, SIZEOF ObjType 4)-> mov pName, eax instring ENDM
Part 3): allocated memory off the heap for this instance (size of the object CLASSNAME) Part 4): moves the pointer of the new instance of CLASSNAME to the newly defined 'instancename'. Then proceeds to call the built constructor line in part 1 (effectively running a constructor for the new object which ties all function pointers together :) The Destructor is pretty well the same:
.data? instancenameData typedef ptr CLASSNAME instnacename instnacenameData ? .code
1) Build the invoke line "invoke CLASSNAME_Destroy, instnacename" 2) Call the Destructor... 3) Free the memory off the heap.. Containment: Yes, i realize there is the possiblitiy of manually getting at instance variables, but im going out on a limb here as ASM programmers to assume that if we are going to build a class object and create set/get's for it, that we will use the actually defined methods rather than confuse things with direct manipulation. I would however be interested if you think its possible to do so without adding to the complexity it the user. I like the fact all i have to do in add Objects.inc to a file, and then each object as a separate .asm, the end :) Last Thought to everyone: get/set or Get/Set ????? ~ I see no real difference but if this is a hang-up for people its a 2 second tweek to take care of.. If people start to enjoy this, give me future ideas too, and i will try to implement them in a next version (with credit to Yourself, and Ernie of course :P) NaN
DESTROY MACRO pName, ObjType LOCAL instring instring CATSTR
,<&ObjType>,<_Destroy, pName> instring invoke GetProcessHeap invoke HeapFree, eax, NULL, pName ENDM
Nan, Please don't think I'm 'bothered' by the adaptations you made to what started as 'my' code. That's why I released it, so people could use it, make it into something else. My main reason to suggest changing "coinvoke" to "METHOD" is so the error message it generates makes sense. When I got home tonight I finally noticed that you do call constructor and destructor functions, you just don't include them in your object model. Containment isn't just to 'keep you honest'and not peek at private variables (though I would try to loosely enforce that anyway). It's also about keeping the vtable hidden (though you assign yours in the constructor, so that's not a problem). It's more about variable name reuse, and code reuseability. A well-written class is asm can be reused in other projects just as in C (with a little more work if you need to inherite from it). I use containment mostly as a convienence in keeping what code was doing what organized.
Sorry all, While i was writing a tutorial on how to use the creator tool efficiently, I found a bug in it, as well as some better optomizations to the Include file. The tutorial is ~80 % complete. Its a design walk thru to build your own LINKLIST Class, using a nested LINK Class that will store Any Object Instance (by my the tool) as its Data. I have sucessfully written the code entries, and the class works beautifully :), i just have to finish the tutorial now, re-compile the tool and zip it all together as one :) So basically, play with what you got, but there is another version comming tomorrow, sorry for jumping the gun on ya's.. Ernie, I have decided to move the DESTRUCTOR into the class and not the constructor, if this is any interest to you. I really dont know of C's format of containing objects, this is all basically my own brainstorming, but it doesnt seem to be half bad thus far. If you think you can help me down a better path please do :), i want to be able to keep this tool robust if i can. As well if you think you can better it with your Containment routines i would also consider incorporating them in. BTW: thanx for the tip on the METHOD/COINVOKE thing, i totally overlooked that one... LOL :D NaN
NaN, Iím very interested but the link is currently broken... while you're fixing? Anyway... I wanna I wanna! ;) On the inheritance thing... this is off the cuff so take at that... Arenít you just tacking on fields to the parent structure(s)? Seems to a straightforward way to do it... for instance
Multiple inheritance gets to be a bit tricky in resolving exact collisions in field names & overloaded functions that have the exactly the same parameter shape. You might want to consider the technique of allowing (dot?) specifiers to resolve these types of collisions. But Iím curious as to how you envision things. Sooo... I eagerly await your tute :) Ernie, Iíve got moving woes (& new job excitement) too. I have to say Iíd be interested in your IDE. As I told Hiro... I'm, the pesky dweeb that won't go away :D... To quote a wise sage "I'll be back." rafe
Child Struct Parent1 Struct Parent1Field1 Parent1Field2 Parent1FuncAddr1 ;only needed for run time polymorphism End Struct ChildField1 ChildField2 ChildFuncAddr1 ;only needed for run time polymorphism End Struct
I've always had a problem with the concept of how to impliment inheritance. Take the given sturcture:
While this accomplishes some inheritance goals, it don't get all the way there. Inheritance has as its main goal the enforcement of relationships. If class Foo inherits from Bar, then Foo IS A Bar. If Blob inherits from both Foo and Bar, Blob HAS A Foo and HAS A Bar. And that's still ignoring method 'overrides.' The biggest problem with this struct is it leads to ugly code. If I delcare MyFoo as this Child, to invoke it's methods I must do the following:
Child Struct Parent1 Struct Parent1Field1 Parent1Field2 Parent1FuncAddr1 End Struct ChildField1 ChildField2 ChildFuncAddr1 End Struct
That's OK, but what about a Parent method call?
METHOD MyFoo, Child, ChildFuncAddr1, (arguments if any)
Ewww, so you're stuck remembering where the methods were inherited from. Messy. That's why I left the CoLib at simply inheriting Methods only, and no implimentations. This is simple to do in macros. One could do something similar here, leaving open the question of implimentation inheritance and overrides. (Implimentations in CoLib are completely "manual," done by the class author as data assignments.) I suppose a suitable macro could be devised, such that if a given inherited method is not defined, the pointer assigned in the constructor is to the orgional code. If it IS defined, the pointer is to the new code. But even thinking of writing this macro, which has to 'know' about both the old class and the new class makes my brain hurt (and I have thought about it and have the scars to show). Maybe some other really clever chap could come up with a way.
METHOD MyFoo, Child, Parent1.Parent1FuncAddr1, (arguments if any)
Well as for me, Im Burnt... :P I will tackle that sometime down the road. But i do come with gifts :) - I updated the Creator Tool, pounded out a bug or two. - I also finished a tutorial on making a Linked List Class - There is a suporint example using this linked list in a Dialog Box based window to tear through and understand.. Anywho.. go get it if your intersted in toying with them. Please give me feedback on what would make the tool better. Get it on my site again : HERE Enjoy all NaN
I haven't taken a look at the code, yet. So, this is just a blind stab in the dark. :) But could you create unique varibles for each method of each object, and then just check to see if that varible is defined. If is isn't we get the object type and check to see if it's method is define. Loop. With Ernie's example above we would have:
...which would be created in the constructor.
BarIsA Object FooIsA Bar BlobIsA Foo
...created in the METHOD macro. It's seems like I'd work to me. I take a look at the code and try to come up with a macro.
BarMethod001 BarMethod002 BarMethod003 FooMethod002 BlobMethod003
Sorry for opening a can of worms & then running out, but I have to tear down the computer tonight & then drive for a few days. NaN, Better believe I'll have a look... well... on the other side. Thanks! Ernie, Your're right, having to remember where things come from defeats the purpose of OOP. But multiple inheritance usually winds up being a mess anyway. Having said that, of course one would allow anyone enuf freedom to do as they please... good, bad, or ugly. Maybe I'm a bubble-headed optimist but I'm not convinced that this is that hard to do. Start with single inheritance first in V1, then refine the design (V1.n); later, in V2, add mutiple inheritance etc. I firmly beleive in the baby-steps approach to program designs. The macro/lexical replacement approach may wind up & being difficult to without some more help from the IDE, hence, my interest in what you're up to on that front. But having said that... BitRake, Mmmm.... I'd like to see that too as I've been wrong before. All, I know that I have yet to show you guys anything of substance (BitRake, Sorry! I've especially dogged out on you!) I can see that I pushing when I should be pulling: that is less talking & asking etc. & more doing. Gotta go now... I'll be back. rafe
rafe, don't worry about it. :) We all do what we can. Coding from me means staying up late, or telling my family to get away from me - which isn't easy in a one bedroom apartment. I have hundreds of pages of notes, but not as much code as I'd like to have. All things in time... The idea is basically an assembly-time linked vector table. If the vector doen't exist the parent table is used. Any of the vectors could be overloaded to point to another method, but defaults to the parent object vector table. This message was edited by bitRAKE, on 5/23/2001 2:45:33 PM
Rafe, and others, please do! My intention here is more global. I first want to provide an ez tool to get people thinking its a feasable alternate while coding asm (not a replacement, but in some cases a better choice). If i can get this much attention drawn, its my hope enough constructive feedback will help pound out a good, solid, and robust class object structure. IF (big stretch here) this happens, hopfully a practical code base can be developed hosting various classes to various purposes. Hiroshimator outlined a while ago he planned to implement a code base in the next message board, so im hoping i can get the ball rolling here.. :) How far it rolls?? I can't say... BitRAKE, you have sparked my interest a wee bit, but I've promised myself i wouldnt code for a day or too ;) . Im thinking off hand that it may be possible if i build an entirely new design on my little tool. ( I made all my code modular so it shouldnt be a problem ). I will have to think on it some more, but if you hack out something cool, lemme know :D Regards, NaN
And while we're here tossing around ideas, let's not forget to mention 'virtual' classes, ie, those that just give method names and no implementation (as they assume they will be inherited inside another class). My muse keeps hinting to me implimentation inheritance ('II' from now on) can be accomplished two ways: at compile time with a pre-processor (ugly, complicated because it would be equal in complexity to a compiler), or at run time with suitable code. The run time code might work like so: The most derived class would invoke each inherited classes constructors, these in turn invoke up the chain till the base class constructors run and return. As each class is instanced, it of course creates it's object structure and returns a reference to it. The inheritining object, of course just knows the public methods and parameters, yet must make room for private methods and parameters too. No problem: add two 'hidden' methods to each class that the NEW macro knows about: one to get the required size of the object (so room may be allocated for it in the inheritining object), and a COPY_THIS method that transfers the orgional object's pointers and such to the new layout. An overridded function could then just have it's implimentation pointer changed. I know I'm ignoring a lot of details (like how to change THIS for each inherited object) (which BTW could be a stub routine), or how to fail the build on a pure virtual function (one that never got an implimentation), but such a scheme might be worth a little effort. Yes, II is the weakest link in OOP, but much usefull code has been written using these techniques, and is worth defining.
Yaaaaaay! I just hacked out OVERLOADING a method with alternate definitions... which was my formost concern in expanding the functionality of my object structure. Ernie's suggestion of OVERRIDING was exactly what i had in mind. And i believe i can suport Inheritance now Based on BitRAKE's suggestion. Just have to code up the changes needed in the tool to be able to Compile an inherited Class into a new class. Again the format will change slightly... anywho.. good stuff comming :) NaN
Heh, cool. Good work, I'll be looking forward to it. And it wasn't really my idea, it was something I remembered about C++ internals.
Taking asm in this direction is long overdue. I've been taking notes on a method of using XML to encapsulate features of software development. The features could be made up of code/images/sound/documentation. I'm geared toward making this tool for asm, but it could be language/OS independant. It would require a special editor. The code fragments would have all external dependancies outlined and allow versions for different processors/languages. I got most the ideas from what I thought DotNET was (then I read more :) ). I like COM objects, but I think that the same flexiblity should exist at the compile-time level. As an example I'd like to add a feature (say a MRU list) to my program. Then have the documention/icons/bitmaps/sounds for that feature added to my program. The programer should be able to plug that feature's features :P in to their program where they want. But then also have the power to produce a fast small program, or a distributed app. Maybe, something like this exists already? Got any ideas to add? I think this is a good thread to add this in?