lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

After doing a great amount of reading and experimentation I decided that the existing methods for creating read-only tables in Lua 5.1 was untenable. For such a simple thing it seemed rather ridiculous to have to use an empty proxy-table along with or instead of redefinitions of the several table related functions. It seemed that there should be a simpler solution. So I went about poking around in the code and came up with a solution that works for me. You can find the patch below that adds Read-Only table support to Lua-5.1.1. This facility is controlled by the '__readonly' entry in a table's metatable. If the value of '__readonly' is a function it is called with semantics identical to '__newindex' that is:

mt = { __readonly = function(table, key, value) print("Attempted to modify a read-only table!") end }

If the value of '__readonly' is anything other than a function a runtime error is generated. I'm sure if I were a little more acquainted with the code that I could have been a little more clever in this regard (such as taking a custom error as a string)

If I've done something horribly wrong, or have put this in an inappropriate place, or there are other implications that I haven't thought of please let me know. This patch "feels" kind of hackish as I am not intimately familiar with the code base, however, it seems to be working find for me:

	mytab = { key1 = "val1", key2 = "val2" }
	mt = { __readonly = true }
	setmetatable(mytab, mt)
	mytab["key3"] = "val3"
	stdin:1: Attempt to modify a Read-Only Table!
	stack traceback:
        	stdin:1: in main chunk
	        [C]: ?

While some of the existing "solutions" are not too difficult to accomplish in Lua, when trying to implement them in C, it becomes a bit of a challenge for something that should be so simple, and in fact the change to the code was very minimal.

Thank you for your time and consideration,

Michael Grubb

It is a rare thing to compile a piece of software without ANY compiler warnings. Thank you for your attention to detail.

The patch is below:

diff -ruN lua-rot-5.1.1/src/ltm.c lua-5.1.1/src/ltm.c
--- lua-rot-5.1.1/src/ltm.c	2006-11-10 15:39:56.000000000 -0600
+++ lua-5.1.1/src/ltm.c	2006-01-10 06:50:00.000000000 -0600
@@ -30,11 +30,8 @@
void luaT_init (lua_State *L) {
   static const char *const luaT_eventname[] = {  /* ORDER TM */
     "__index", "__newindex",
-    "__gc", "__mode",
-	"__readonly",
-	"__eq", "__add", "__sub", "__mul", "__div", "__mod",
+    "__gc", "__mode", "__eq",
+    "__add", "__sub", "__mul", "__div", "__mod",
     "__pow", "__unm", "__len", "__lt", "__le",
     "__concat", "__call"
diff -ruN lua-rot-5.1.1/src/ltm.h lua-5.1.1/src/ltm.h
--- lua-rot-5.1.1/src/ltm.h	2006-11-10 15:39:59.000000000 -0600
+++ lua-5.1.1/src/ltm.h	2005-06-06 08:30:25.000000000 -0500
@@ -20,9 +20,6 @@
   TM_EQ,  /* last tag method with `fast' access */
diff -ruN lua-rot-5.1.1/src/luaconf.h lua-5.1.1/src/luaconf.h
--- lua-rot-5.1.1/src/luaconf.h	2006-11-10 15:39:47.000000000 -0600
+++ lua-5.1.1/src/luaconf.h	2006-04-10 13:27:23.000000000 -0500
@@ -747,12 +747,6 @@
-@@ LUA_READONLY_TABLES controls whether to enable read-only table
-support by way of the __readonly metatable entry. CHANGE it (define it)
-to enable Read-Only support.
/* =================================================================== */
diff -ruN lua-rot-5.1.1/src/lvm.c lua-5.1.1/src/lvm.c
--- lua-rot-5.1.1/src/lvm.c	2006-11-10 14:26:17.000000000 -0600
+++ lua-5.1.1/src/lvm.c	2006-06-05 10:58:59.000000000 -0500
@@ -140,22 +140,11 @@
     if (ttistable(t)) {  /* `t' is a table? */
       Table *h = hvalue(t);
       TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
-	  if ( (tm = fasttm(L, h->metatable, TM_READONLY)) != NULL )
-	  {
-		  if (ttisfunction(tm)) {
-			  callTM(L, tm, t, key, val);
-			  return;
-		  }
-		  else
-			  luaG_runerror(L, "Attempt to modify a Read-Only Table!");
-	  }
       if (!ttisnil(oldval) ||  /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
-        	setobj2t(L, oldval, val);
-        	luaC_barriert(L, h, val);
-        	return;
+        setobj2t(L, oldval, val);
+        luaC_barriert(L, h, val);
+        return;
       /* else will try the tag method */