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 FunctionNo 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 FunctionI 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 FunctionIs 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? |