Eggdrop Tcl Namespaces

Why namespaces? If you've ever had issues with global variables or procedures in your script conflicting with other scripts, you need namespaces. Namespaces are the closest that Tcl gets to object oriented programming. They allow the programmer to place variables and procedures inside one neat named-package in Tcl so as not to conflict with anything in the global namespace.

Lets Begin!

namespace eval MyScript {
  set response "Hello World!"
 
  bind pub - "hi" MyScript::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }
}

MyScript is the name of the namespace. This will be the prefix used in the name of variables and procedures if they are being called from other namespaces (such as the global). Notice that the bind specifies the full name in the procedure parameter. Another thing to note is that the variable $response resides within the namespace. That means it's not a global variable. So, inside the procedure, it is declared as a variable, rather than global. Note that variables must be declared on separate lines if you have more than one. They cannot be declared in one long line like globals.

catch MyScript::uninstall
namespace eval MyScript {
  set response "Hello World!"
 
  bind pub - "hi" MyScript::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }
 
  bind evnt - prerehash MyScript::uninstall
  proc uninstall {args} {
    unbind pub - "hi" MyScript::respond
    unbind evnt - prerehash MyScript::uninstall
    namespace delete MyScript
  }
}

Rather than forcing users to .restart to uninstall scripts, lets uninstall on rehash. If the user still has the script in the conf, it'll be loaded automatically after the rehash. First of all, binds are not directly associated with the namespace, so they have to be unbound separatly. Then the namespace itself can be deleted. Don't forget to kill any timers that may be in your script here, too. Also, in order to also uninstall/reinstall for users that .tcl source the script, add the top line to call the uninstall procedure. The catch is there so that the bot doesn't crash if the uninstall procedure doesn't exist yet (first run).

set ns "MyScript"
catch ${ns}::uninstall
namespace eval $ns {
  unset ::ns
 
  set response "Hello World!"
 
  bind pub - "hi" [namespace current]::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }
 
  bind evnt - prerehash [namespace current]::uninstall
  proc uninstall {args} {
    unbind pub - "hi" [namespace current]::respond
    unbind evnt - prerehash [namespace current]::uninstall
    namespace delete [namespace current]
  }
}

If you are worried about the the namespace possibly conflicting with another namespace, do something like this. First, set the namespace in a global variable. It's only used in the first two lines, so we unset the global variable after, so as not to clutter up the global namespace. After that, [namespace current] should be used anywhere MyScript was used. Doing this will make it practically impossible for your script to conflict with someone else's.

All Done!