What is the name of the automatic destructor?
Monkey Forums/Monkey Beginners/What is the name of the automatic destructor?
| ||
Hi! Somebody knows the method name of the destructor that is called when the object gets (automatically) destroyed? Can't find it in the documentation nor in the forums. How can I put code into this simple forum? Trying code tags... Strict Class myClass Public Method New() Print("Constructor") End Method Method Destructor:Void() Print("Destructor") End Method Method Delete:Void() Print("Destructor") End Method Method Dispose:Void() Print("Destructor") End Method End Class Function Main:Int() Local c1:myClass = New myClass() Return 0 End Function No preview function before I submit, hope it works. |
| ||
The default constructor is New(). There is no built-in finalizing method for object destruction -- the garbage collector will handle this for you once an object reference goes out of scope. You may, however, flag resources for disposal by setting them to Null. Some mojo and brl functions have dispose methods which handle this. |
| ||
Thanks Nobuyuki! So we need to call object.Destroy() ourself every time. Hmm. Do you know why the following simple code does not work? Strict Function DoIt:Void() Print("DoIt") End Function Function Main:Int() Print("In Main()") DoIt() Return 0 End Function I am on Mac OS X. With HTML target I get no output. If I out-comment the call to DoIt(), I get the output "In Main()", with the call I get no output at all. Same code compiled as target "C++ Tool" is compiled OK by Monkey, but it generates wrong C++ code: "/Users/danilo/Monkey/bin/transcc_macos" -target=C++_Tool -config=Release -run "/Users/danilo/Projects/Monkey/Tests/Test 0002.monkey" TRANS monkey compiler V1.60 Parsing... Semanting... Translating... Building... main.cpp:2045:6: error: variable has incomplete type 'void' void bb_Test 0002_DoIt(); ^ main.cpp:2045:13: error: expected ';' after top level declarator void bb_Test 0002_DoIt(); ^ ; main.cpp:2047:6: error: variable has incomplete type 'void' void bb_Test 0002_DoIt(){ ^ main.cpp:2047:13: error: expected ';' after top level declarator void bb_Test 0002_DoIt(){ ^ ; 4 errors generated. TRANS FAILED: Error executing 'g++ -Wno-parentheses -Wno-dangling-else -arch i386 -read_only_relocs suppress -mmacosx-version-min=10.3 -O3 -DNDEBUG -o main_macos main.cpp', return code=256 Done. I can't see the error in this code. Monkey compiler does not complain, but generated code is wrong or does not work. Thanks in advance! |
| ||
The code is valid monkey code, it runs fine on my machine on both HTML5 and GLFW (OSX 10.9, MonkeyPro75d). Maybe something with your setup, can you run the examples that come with Monkey? |
| ||
I'm using latest final, Monkey Pro 76d. I will check going back to 75d... |
| ||
With 75d I got:"/Users/danilo/Monkey/bin/transcc_macos" -target=Html5_Game -config=Release -run "/Users/danilo/Projects/Monkey/Tests/Test 0002.monkey" TRANS monkey compiler V1.56 Parsing... /Users/danilo/Projects/Monkey/Tests/Test 0002.monkey<1> : Error : Invalid module identifier 'Test 0002'. Done. OK, renamed my file "Test 0002.monkey" to "Test_0002.monkey" and it works now with 75d. Tried again with 76d, and it works now, too. Problem was the space in the filename. Thanks guys! |
| ||
Danilo: You will find a few other things that Monkey Doesn't like in file names. |
| ||
I understand. Only english characters, underscore and numbers are allowed in filenames. I guess filenames also can't start with numbers then. If Monkey takes the filename in the code generator, couldn't it replace unknown characters with underscores automatically, or something like that? Filename "01 Test 0001!" could become module name "_01_Test_0001_" internally. |
| ||
Think Java. In java your class name and file name must be the same. Except in Monkey's case if you dare to have a file name that has the same casing as a class name, expect issues. |
| ||
Is it allowed to make feature requests here? (and if so, what's the best forum category for it?) I would like to see destructors added to the language. It should inherit from 'Object', maybe as a virtual/abstract function. Every class in a hierarchy can have it's own destructor. The highest destructor in the hierarchy gets called when the object gets released and can call super.Destructor() after it has done it's own cleanup stuff. Or all destructors in the hierarchy get called automatically, starting at the highest level. Sometimes you have to cleanup something before the object gets destroyed, especially if you do API programming. Or a file class could automatically close the file if it is still opened because the user forgot to call f.close(). Doing this automatically can prevent errors and is also nice to use. No need to call obj.Destroy() for every object by hand, and if you forget such a call, it is done automatically and no leaks appear... |
| ||
Made a test for collecting objects and cleanup at program end. Works only as targets "C++ Tool" and "GLFW" for me, here on Mac OS X Mavericks with Safari 7.0.1. (EDIT: Works as HTML target on Windows) (EDIT 2: Works as HTML target on Mac OS X now, after restarting Safari/Computer) Strict Class Exception Extends Throwable Field exception:String Method New( msg:String ) Self.exception = msg End Method End Class Class BaseObj Abstract Private Global objList:List<BaseObj> = New List<BaseObj> Field className:String Method _reg:Void(s:String) objList.AddFirst(Self) className = s Print(">>> Registered object of type: "+s) End Method Method New() Print(">>> BaseObj::Constructor") className = "Class BaseObj" End Method Public Method ToString:String() Return className End Method Method Delete:Void() objList.RemoveFirst(Self) 'Print("Removed object of type: "+className) Print(">>> BaseObj::Destructor ("+className+")") End Method Function Cleanup:Void() For Local o:BaseObj = Eachin objList o.Delete() Next End Function End Class Class MyClass Extends BaseObj Public Method New() Print(">>> MyClass::Constructor") _reg("Class MyClass") End Method Method Delete:Void() Print(">>> MyClass::Destructor") Super.Delete() End Method End Class Class Address Extends BaseObj Private Field _name:String, _street:String, _zip:String, _town:String Method New() Throw New Exception(">>> >>> Address Constructor with 0 arguments is private") End Method Public Method New(name:String, street:String, zip:String, town:String) Print(">>> Address::Constructor") _reg("Class Address") _name = name _street = street _zip = zip _town = town End Method Method ToString:String() Return _name + ", " + _street + ", " + _zip + ", " + _town End Method End Class Function DoIt:Void() Local c2:MyClass = New MyClass() 'c2.Delete() End Function Function Main:Int() Try Local c1:MyClass = New MyClass() Print( c1.ToString() ) 'c1.Delete() Local adr:Address = New Address("John S.","The Street","12345","N.Y.") Print( adr.ToString() ) 'adr.Delete() DoIt() 'Local adr2:Address = New Address() ' why private constructor can be called? Print("------------") Print("Program End.") Print("------------") Catch ex:Exception Print( "PROGRAM EXCEPTION: " + ex.exception ) End Try BaseObj.Cleanup() Return 0 End Function Is it possible to make the default constructor New() private somehow, so it can't be called? Like in the "Class Address", where I wanted to disallow the default New() and force the use of New(name, street, ...) |
| ||
Is it allowed to make feature requests here? (and if so, what's the best forum category for it?) I recommend you post it in the 'Monkey Programming' forum. It's sort of the general go-to forum for requests and such. You can also alternatively post in the 'Bug Reports' area as a request. I've seen a few people do it, although I discourage it because it clutters the already cluttered 'Bug Reports'. Also, regarding your cleanup code, it looks like you're trying to write Jimmy-proof code. While it might be good for your purposes, it does not necessarily fit every single case. Which is why Monkey will likely never get this. If it does, then good, if it doesn't, that doesn't bother me either. The neat part about Monkey is the fair bit of flexibility it gives to develop a system you want. Is it possible to make the default constructor New() private somehow, so it can't be called? This is probably the best solution to the private new issue.Function Main:Int() Local show := New Example(10) Print show.value show = New Example() End Class Example Method New() Error("You cannot initialize Example this way") End Method New( value:Int ) Self.value = value End Field value:Int End |
| ||
Thanks Goodlookinguy! I will read the complete documentation and the book "Monkey Game Development" now to learn some of the basics. |
| ||
As a rule I try stick with to this convention and I haven't had any problems: Monkey File Names: all lowercase letters, no spaces or special chars Monkey Class Names: same as the filename except with first letters capitalised. e.g. mymonkeyfile.monkey Class MyMonkeyFile |
| ||
I will read the complete documentation and the book "Monkey Game Development" now It would also be worth your while having a look at invaderJim's tutorials.Like NoOdle. I also try and stick to a naming convention. Monkey File names: Just like NoOdle are all lower case, no spaces or special characters. But I do try to give them a descriptive name. Any file that is a class or contains classes that are closely tied to one an other will start with a c and the name of the primary class. Files that need to be seen by any other module tend to go in a file called global or if this file gets too big it can be broken down and each section then starts with a g. I use a file that is named exactly the same as the application. It is here that I place the primary modules to import and the program entry Main function. The file for the extended App class when using mojo usually gets named either main, cgame or the application name starting with a c depending on the applications name. Monkey Class Names: Just like NoOdle does. But all Classes start with a capital C e.g. cmysprites.monkey Class CMySprites. Constants: are all capitals Functions: First letters of each part always capital e.g Function MyFunction:Void() Variables: Lower case. Underscores allowed where necessary to improve readability. And certain structures such as lists prefixed with an abbreviation of three letters and a underscore. e.g List prefix lst_ One more thing when naming file names don't use names that are reserved words. e.g import as it confuses the compiler. |
| ||
I thought I could prevent the problem when I write my classes with C++, but it looks like Monkey and its garbage collector do not release imported C++ classes correctly. class_test.cpp #include <iostream> class Console { public: Console(void) { std::cout << "Console::Constructor" << std::endl; } ~Console(void) { std::cout << "Console::Destructor" << std::endl; } void Out(String _s) { std::wstring s( _s.Data() ); std::wcout << s << std::endl; } void Delete(void) { delete this; } }; class_test.monkey Import "class_test.cpp" Extern Class Console Method Out:Void(s:String) Method Delete:Void() End Public Function DoIt:Void() Local c1:Console = New Console c1.Out("Hello from Monkey::DoIt()") 'c1.Delete() End Function Function Main:Int() Local c2:Console = New Console c2.Out("Hello from Monkey::Main()") 'c2.Delete() DoIt() Return 0 End (compiled as target "C++ Tool" on Mac OS X) Output code for the function DoIt(): void bb_class_test_DoIt(){ Console* t_c1=(new Console); t_c1->Out(String(L"Hello from Monkey::DoIt()",25)); } Shouldn't Monkey add a 'delete' to the generated C++ code, because the pointer is going out of scope? The local variable "Local c2:Console = New Console" is not released correctly here. Without using pointers for local class variables, C++ takes care of the cleanup automatically: class_test_cpp.cpp // // g++ class_test_cpp.cpp // ./a.out // #include <iostream> class Console { public: Console(void) { std::cout << "Console::Constructor" << std::endl; } ~Console(void) { std::cout << "Console::Destructor" << std::endl; } void Out(std::string s) { std::cout << s << std::endl; } void Delete(void) { delete this; } }; void DoIt() { Console c1; c1.Out("Hello from DoIt()"); } int main() { Console c2; DoIt(); c2.Out("Hello from main()"); return 0; } I expected Monkey to do the same for local class variables. With the test code above, imported C++ classes seem to get never released by Monkey. What did I do wrong? When I call DoIt() a few million times at runtime, and the objects get never released, this could lead to out-of-memory problems. Is it possible to add C++ objects to the garbage collector somehow, so it takes care of it? |