Overwriting functions

Monkey Forums/Monkey Programming/Overwriting functions

Hezkore(Posted 2014) [#1]
Is there any way to overwrite functions?
Specifically the Print function.

I'm writing a console for a project I'm working on.
And I want to redirect all Print text to that console window.
I can use a ConsolePrint function myself, but a lot of modules still use the old Print function.
So I was wondering if there was any way to direct Print function to my ConsolePrint function?

Alternatively, is there a way to read already printed text?


Danilo(Posted 2014) [#2]
What's your target? This works with targets C++, GLFW, and HTML5 on MacOSX:
Extern
    #if TARGET = "html5"
        Function Print:Int(x:String) ="bb_OverwriteFunc_MyFunc"
        Function bbPrint:Int(x:String) = "print"
    #else ' C++, GLFW
        Function Print:Int(x:String) ="bb_OverwriteFunc_MyFunc"
        Function bbPrint:Int(x:String) = "bbPrint"
    #endif
Public

Function MyFunc:Int(text:String)
    bbPrint("OUTPUT: >> "+text)
End

Function Main:Int()
    Print "Hello Monkey X!"
    MyFunc("myPrint")

    bbPrint("original bbPrint")
    Return 0
End

You have to lookup the function names in the generated sources for the specific target.
Generated function names could also change with new MX releases.


ImmutableOctet(SKNG)(Posted 2014) [#3]
I was actually going to write a response to your initial post earlier, but something came up.

Alright, so what you want can't be done in Monkey without platform specific hacks. But, in general, a module shouldn't be printing to the console without some kind of toggle, and really shouldn't be outputting to your in-game console to begin with. Considering you'll always be dealing with 'Strings', your best bet is to write a custom command and use a preprocessor variable to toggle if it should output to the console using 'Print' or not. I did something like this with my 'util' module, and that code can be found here. The thing is, my system is integrated into a specific project of mine, but the idea's the same; just write a wrapper and add what you need to.

Anything further would tread on language specific territories, which can be annoying, not to mention a bit overkill. The only time you'd absolutely need to do that kind of thing is with some rather odd native code.

Handling lines with one of Monkey standard containers (Or perhaps a generic enumerator-based system) is my recommendation. That should hopefully fit your needs. And of course, one of the best parts of having a wrapper is the ability to not only have suffixes and prefixes, but also different suffixes and prefixes for each output.

As for overriding/overwriting existing functions, this can not be done in the way you're asking. As much as I wish this was a thing, internally that would be a headache and a half. But there is a way to use the same name as an existing function. This functionality is provided by the 'Alias' keyword. Here's an example:

The above example outputs the line specified in lowercase.

But then, here's the thing about aliases, in the case of functions, they allow redefinition of something's name for the current module, but they don't locally redefine names in modules importing that module. This doesn't mean your alias won't be available to the module which imports the one with your alias, it means your alias is applied as what it backs (A function name). In turn, you have the usual default imports for Monkey (The 'monkey' module(s)) already providing 'Print' (AKA: 'lang.Print'). This makes 'Print' and other default functions a special case. You can use aliases for those commands, but you aren't going to get very far making aliases everywhere. Also keep in mind that aliasing allows you to reuse the original local name for something else, but that's completely optional. You could easily set an alias just for the sake of having two names for something.

Type aliases can be used for any type (Including the default types), but they don't allow changes (Or even aliases) to local type-names (Just as you can't alias functions which reside in the current module). This means you can't write something weird like: "Alias String = Float", all actual types are immutable. The names you get secondhand from another module, are not actual types, but instead just like aliases, so you can redefine them there (Which will then make those names normal for that module's importers). With all of this in mind, you realize that aliases are just for name resolution. Because of this, situations like: " Local A:Address = "127.0.0.1" " where 'Address' is an alias to 'String' is no different than using the actual type. This means nothing distinguishes between them. Therefore, 'Address' can not be used to distinguish in situations like function overloading.

This exact idea of redefining functions is what lead me to appreciate the designs of good compilers.

Anyway, I hope this really long post helps. Just make a wrapper function, you won't kick yourself later.

EDIT: Formatting.