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

P.S.
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",
-#ifdef LUA_READONLY_TABLES
-	"__readonly",
-#endif
-	"__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_NEWINDEX,
   TM_GC,
   TM_MODE,
-#ifdef LUA_READONLY_TABLES
-  TM_READONLY,
-#endif
   TM_EQ,  /* last tag method with `fast' access */
   TM_ADD,
   TM_SUB,
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 @@
#endif
-/*
-@@ 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.
-*/
-#define LUA_READONLY_TABLES
/* =================================================================== */
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 */
-#ifdef LUA_READONLY_TABLES
-	  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!");
-	  }
-#endif
       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 */
     }