Page 1 of 4

The Shared Namespace and You

Posted: Thu Jan 14, 2010 2:54 am
by ixokai
There's been a lot of discussion on #mudlet which revolved around namespaces, and the few hard-core scripters there reached a consensus, but then it was just sort of assumed and/or noted and we all moved on to more interesting topics.

But since a lot of people -aren't- on IRC, I thought it would be wise to mention some thoughts we ended up thinking was The Way To Do Stuff.

As you should know from the manual, Mudlet doesn't have "namespaces"-- every script that you run, be it a script-script, or some lua code in a trigger or alias, shares a single global context. This makes certain things really easy, but also starts tripping people up a little if we start using systems from more then one person.

There's a lot of talk going on about shared / external modules, which is likely to be implemented in some form in the future -- which will make it a lot easier for you to pick and choose stuff which people release and integrate it into your profiles. You can already do that, but it'll be easier. So people are likely to do it more. :)

With that in mind, anyone writing code now may want to take a little bit of time to "future-proof" your code by adopting some strict naming conventions - that being, instead of using <name>, use <module>.<name>. You'll be putting your module-specific variables into a table.

This requires a little bit of setup, which I place in the main group of my package, which we'll assume I'm using a prefix of 'package' for:

Code: Select all

package = package or {}
Then, I might set health on my package by doing:

Code: Select all

package.health = matches[2]
For functions, there's some special syntax which allows you to define a function inside that package by doing:

Code: Select all

function package:do_my_thing()
  echo("Hi.")
end
If you do any activating/deactivating of aliases, triggers or timers by name-- you'll want to do something similar with them as well.

Me, I'm going to end up using "<system>.variable" for all the stuff I do which is intended for this monstrosity of a system I'm working on that I so haven't named, and then "ixokai.variable" for one-off's that I might have that are just generally useful.

This isn't a requirement, just a recommendation. If you do it early, you won't have any trouble running your code with other peoples -- well, you'll have less trouble at least.

HTH,
--Ix

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 6:40 am
by demonnic
stickied

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 5:12 pm
by tobiassjosten
Lua have modules and closures to solve this very problem. Why would you want to promote this anti-pattern over those features?

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 6:41 pm
by Wingard
Because that's laggy. This isn't.

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 6:55 pm
by Denarii
No, it's not.

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 9:09 pm
by Heiko
tobiassjosten wrote:Lua have modules and closures to solve this very problem. Why would you want to promote this anti-pattern over those features?
Sorry, but I can't see how modules and closures are related to the topic of this thread. Lua has a shared namespace and Lua "modules" are still sharing the same namespace as the rest of the scripts.
In the beginning of Mudlet we've made a decision to use a single interpreter for everything because this approach has many advantages. As more and more packages are being released for Mudlet, this thread is an important reminder for package authors to make sure that they use variables and function names that are going to be unique.
myHealth won't be a good choice, but myPackageName.myHealth wil be better.

Re: The Shared Namespace and You

Posted: Thu Jan 14, 2010 9:10 pm
by ixokai
The problem with modules is they are external to Mudlet; mudlet scripts live in their own globally shared namespace. All Lua scripts in Mudlet are loaded into that global context. Modules are external, and while you may use 'require', it won't stop people from importing mudlet packages and having things get stomped. Thus, they're a problem for distribution-- not to mention a cross-platform placement issue.

Although the consensus has changed to doing,

Code: Select all

if not prefix then
    prefix = {}
end
And then

Code: Select all

prefix.mywhatever = true

Re: The Shared Namespace and You

Posted: Fri Jan 15, 2010 11:53 am
by davidk
tobiassjosten wrote:Lua have modules and closures to solve this very problem. Why would you want to promote this anti-pattern over those features?
Lua modules are tables which contain all the functions and variables, so in the end the result is the same. If you thought of the "module ()" function, that function is quite debated even in "common" Lua (see http://lua-users.org/wiki/ModuleDefinition and http://lua-users.org/wiki/LuaModuleFunctionCritiqued). In Mudlet it makes no sense anyway as the scripts don't use require to load other parts.

Closures are something else, they just enable dynamically created functions to share state.

Re: The Shared Namespace and You

Posted: Sat Jan 16, 2010 10:32 pm
by tobiassjosten
Wingard wrote:Because that's laggy. This isn't.
I would love to see your sources. Yeah, that's a challenge.
Heiko wrote:Sorry, but I can't see how modules and closures are related to the topic of this thread. Lua has a shared namespace and Lua "modules" are still sharing the same namespace as the rest of the scripts.
I think we are aiming for the same solution - containers. I'm just thinking that programmers shouldn't impose on other programmers'/users' namespaces. If you distribute your code as a Lua module instead, you can leave the actual implementation up to the user. And the world will be a better place.

Eg, if you pick ixokai (or something generic as "combat") as the container name, then you are effectively barring anyone else from using that same name. Or rather, you are begging for collisions. If you instead use modules, then the end user is free to pick and combine any goodies he/she sees fit.
davidk wrote:Lua modules are tables which contain all the functions and variables, so in the end the result is the same.
No. The distinction is that Lua modules, if done properly, does not pollute the users' namespace.
davidk wrote:Closures are something else, they just enable dynamically created functions to share state.
Consider my example module, tobiascounting.lua:

Code: Select all

local x = 0
module(...)
function tick()
  x = x + 1
  return x
end
Then the implementation in the user's script file:

Code: Select all

counter = require("tobiascounting")
print(counter:tick() + counter:tick()) -- prints 3
The user handles his/her own naming convention and states are handled by scoping. That is pretty much the application of a closure.

Re: The Shared Namespace and You

Posted: Sun Jan 17, 2010 12:20 am
by ixokai
tobiassjosten wrote:
Wingard wrote:Because that's laggy. This isn't.
I would love to see your sources. Yeah, that's a challenge.
I would be the source of that claim; though I never actually said laggy or implied anything as major as that implies. I have since retracted and changed the advice accordingly (you'll notice the first-post has been changed)
tobiassjosten wrote:
Heiko wrote:Sorry, but I can't see how modules and closures are related to the topic of this thread. Lua has a shared namespace and Lua "modules" are still sharing the same namespace as the rest of the scripts.
I think we are aiming for the same solution - containers. I'm just thinking that programmers shouldn't impose on other programmers'/users' namespaces. If you distribute your code as a Lua module instead, you can leave the actual implementation up to the user. And the world will be a better place.
The point is, though, that you *can't* distribute your code as modules. It just doesn't work like that. You can't say it does: a Mudlet script is much, much more then just Lua. It is triggers, aliases, timers, and such. You can get some of that power by loading everything into a script and doing temp*'s to get them, and I considered that: but you can't fully replicate the power of Mudlet triggers through functions, so its a no-go.

There really is just no comparison. Mudlet lua scripts are just one small piece of the problem. Triggers, aliases, and the like, all contain lua code which can't be encapsulated into a module and distributed as a module. It simply can't, and so Lua's module / require functionality is just useless for this. Beyond that, there are very real distribution problems. On the mac for example, it will be VERY difficult to support a Lua search path which can easily find any sort of external modules-- I can go into why if you'd like, but its a real issue.

Further, using external modules would take you out of Mudlet's script editor. Perhaps you want to live there, but many don't, and if we're requiring anyone to do quality shared packages to do all the code in an external editor, that's a problem.
tobiassjosten wrote: Eg, if you pick ixokai (or something generic as "combat") as the container name, then you are effectively barring anyone else from using that same name. Or rather, you are begging for collisions. If you instead use modules, then the end user is free to pick and combine any goodies he/she sees fit.
Given that modules can't solve our problems or prevent collisions as we can't actually put much of our systems into them, and given that Mudlet doesn't offer isolation between components (intentionally and for good reasons), then us using our own top-level table namespaces is the best possible compromise solution.

Yes, there's a chance that someone might choose to use a similar top level name. But its actually a really small chance, and we can mitigate it as a community by just making people know what we're using. There's four out there that I'm aware of so far: crucible, mantis, venom, and I so claim 'ixokai' -- a word I invented years ago and which has never been used by anyone but me :P I hear demonnic claims his name, too.

--Ix