I use LuaJit for extending a plain C application (using the Lua C API). The host application does manage memory for a lot of objects that I have written wrappers for in Lua.
Now I would like to be able to delete objects from within the lua function, i.e. implement a delete function. I would like to illustrate the problem at hand with the following outline of the problem.
Basically my lua user data structure looks something like this.
struct my_lua_container {
size_t obj_db_index;
};
where obj_db_index is an index for the local object database. With the Lua C API I have created a lua-function query_object(...) that retrieves a lua metatable based on this user data and offering an API for managing the db object.
I am now planning to introduce a method my_db_object:delete() in the metatable API. :delete() could invalidate my_db_object by overwriting the variable with 0 or setting another member variable. The problem however is, that all references to the deleted object ought to be invalidated. Consider this lua code:
local p = query_object("1")
local q = query_object("1")
p:delete()
q:do_something() -- <=== q still contains a obj_db_index
Now I wonder how to solve this potential conflict. The two main problems are:
An invalid obj_db_index could be an invalid index. This is actually probably caught by the code already, so it isn't pretty but alright
after deletion, the index might be reused and this could lead to subtle errors when other references still use the old index.
What are strategies to deal with this?
My idea might be a little time-consuming but this would be ok in the event of deletion:
Is there some Introspection that I can perform on user data objects? Like iterating over all user data objects with the same type in order to invalidate my_db_index when the deletion is triggered
Maybe a little late, but… The solution is to put new objects into weak table and never create objects already stored there.
-- this should be really C, but for readability, we write it in Lua pseudocode
registry.my_cache = setmetatable({ }, { __mode = "v" })
function push_object(db_id)
local object = registry.my_cache[db_id]
if object == nil then
object = lua_newuserdata(db_id)
registry.my_cache[db_id] = object
end
end
assert(push_object(1) == push_object(1))
Now only unique db_id's go from C side to Lua side, problem almostly disappeared.
But there is one more detail to take care of. Garbage-collection of userdata has two phases: finalization and removal from weak tables. There are moments, when userdata is finalized, but still present in weak table, so the code above may return finalized userdata to the user. Additional check should be made, and if ud is finalized, it should be manually removed from table first.
function push_object(db_id)
local object = registry.my_cache[db_id]
-- check vitality first
if is_finalized(object) then
registry.my_cache[db_id] = nil
object = nil
end
if object == nil then
object = lua_newuserdata(db_id)
registry.my_cache[db_id] = object
end
end
How you know whether userdata is finalized is up to your implementation of finalization method (metatable.__gc).
Related
I've been working on Ruby Koans and I've gotten to this part that I don't understand too well. Specifically, it's the about_dice_project, where they ask us to define a class to pass several pre-set tests. Originally, my class looked like
class DiceSet
attr_accessor :values
def initialize
#values = []
end
def roll(num)
num.times { |i| #values[i] = rand(1..6) }
return #values
end
end
But this failed the test below
dice = DiceSet.new
dice.roll(5)
first_time = dice.values
dice.roll(5)
second_time = dice.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
And I realized after some testing that both first_time and second_time have the same object_id. So I looked on stackoverflow for some help and found this answer, which doesn't answer my question directly, but I did find a major difference in our code; namely, that instead of using the "num.times" way of rolling the dice, goes instead with
#values = Array.new(num) { rand(1..6) }
and this does pass the above test.
After finding this, I was trying to figure out why my original code didn't work, and so I thought that maybe Ruby was passing by reference, and that's why when the dice-rolling-method created a new array instead of modifying the existing array, that was a new object id created. But then I found this question, which says that Ruby is pass-by-value, and if that was the case, then I would have expected that my original way would work.
So now I'm confused again, and I'd like to ask - where did my line of thought go wrong? Is Ruby pass-by-value only in certain cases? Have I misunderstood what pass-by-value/reference even means? Is my issue not related to pass-by-value/reference at all?
You can see object in ruby as a reference to data.
So even if Ruby is pass by value, the thing got copy is object, a.k.a a handle to underlining data.
Even from the answer you link to, had said:
Variables are always references to objects. In order to get an object that won't change out from under you, you need to dup or clone the object you're passed, thus giving an object that nobody else has a reference to. (Even this isn't bulletproof, though — both of the standard cloning methods do a shallow copy, so the instance variables of the clone still point to the same objects that the originals did. If the objects referenced by the ivars mutate, that will still show up in the copy, since it's referencing the same objects.)
Say I wanted to store objects statically inside their own class. Like this:
public class Foo
{
private static int instance_id = 0;
public static List<Foo> instances = new List<Foo>();
public Foo()
{
instances[instance_id++] = this;
}
}
Why?
I don't need to create unique array structures outside the class (one will do).
I want to map each object to a unique id according to their time of birth.
I will only have one thread with the class in use. Foo will only exist as one set in the program.
I did searching, but could find no mention of this data structure. Is this bad practice? If so, why? Thank you.
{please note, this question is not specific to any language}
There are a couple of potential problems I can see with this setup.
First, since you only have a single array of objects, if you need to update the code so that you have lots of different groups of objects in different contexts, you'll need to do a significant rewrite so that each object ends up getting associated with a different context. Depending on your setup this may not be a problem, but I suspect that in the long term this decision may come back to haunt you.
Second, this approach assumes that you never need to dispose of any objects. Imagine that you want to update your code so that you do a number of different simulations and aggregate the results. If you do this, then you'll end up having your giant array storing pointers to objects you're not using. This means that you'll (1) have a memory leak and (2) have to update all your looping code to skip over objects you no longer care about.
Third, this approach makes it the responsibility of the class, rather than the client, to keep track of all the instances. In some sense, if the purpose of what you're doing is to make it easier for clients to have access to a global list of all the objects that exist, you may want to consider just putting a different list somewhere else that's globally accessible so that the objects themselves aren't the ones responsible for keeping track of themselves.
I would recommend using one of a number of alternate approaches:
Just have the client do this. If the client needs to keep track of all the instances, just have them always create the array they need and populate it. That way, if multiple clients need different arrays, they can do so. You also avoid the memory leak issues if you do this properly.
Have each object take, as part of its constructor, a context in which to be constructed. For example, if all of these objects are nodes in a quadtree, have them take a pointer to the quadtree in which they'll live as a constructor parameter, then have the quadtree object store the list of the nodes in it. After all, it seems like it's really the quadtree's responsibility to keep track of everything.
Keep doing what you're doing, but using something with weak references. For example, you might consider using some variation on a WeakHashMap so that you do store everything, but if the objects are no longer needed, you at least don't have a memory leak.
C functions that are passed to Lua to so that Lua can call native functions are static functions and thus not related to an object instance.
In my application, I have multiple sessions. Each session runs on its own thread, has its own data and its own scripts, and a script of the session N must be able to access the data of that session N.
The problem is that when you register a native C function to be callable from Lua, I can't pass the instance of the session object to make it available in the static Lua function.
One possibility could to be store the instance of the session into a static variable that can be called from the static C function (called from Lua), but this looks dirty and would require synchronization that could cause some scripts to hang.
A second possibility might be to create an Lua object that represents the session and call member methods on it so that, in my C function, I would have a way to access the Lua object representing the session ("this") and retreive the actual native session instance represented by this object. But I have no idea how to do that.
Is there a way to create Lua objects representing native object instances in Lua so that native Lua functions would have access to that native object instance ?
When you register a C function with Lua, you can store additional values as so-called "upvalues". The C function can then retrieve those values when it's called:
// ...
// push session instance pointer
lua_pushlightuserdata( L, (void*)get_current_session() );
// create a closure with one upvalue
lua_pushcclosure( L, my_static_C_function, 1 );
// ... (the resulting Lua function is at the stack top now)
In your static C function you access the instance data like this:
static int my_static_C_function( lua_State* L ) {
session_t* instance = (session_t*)lua_touserdata( L, lua_upvalueindex( 1 ) );
instance->do_something();
return 0;
}
Since each session has its own thread, why don't you link them together?
Whenever your function is called, get the session from the current thread.
You might want to take a look at the manuals about userdata.
Since "Each session runs on its own thread" you could simply save session data as static thread-local.
Better would be to transport session data by userdata, with a metatable bound for associated functions, and don't rely on static stuff.
As last alternative, let's combine: save session data as userdata/pointer Lua-state-local.
In all cases you have to care about class instances destruction because userdata are freed in C-style, same as thread data.
I am working on a project written in C++ which uses Lua as a scripting language.
In order to facilitate debugging we implemented a network debugger which receives Lua code, runs it, encodes the return values in Json and sends that string back.
I managed to implement that for tables, but now I am stuck with variables stored in userdata.
E.g. I have this Lua code:
Elements.Avatar.testVar = 5
Elements.testVar = 15
return Elements
// result
{
"result0": "{Application:userdata; Avatar:userdata; Physics:userdata; testVar:15; }"
}
Application, Avatar and Physics are objects that have been created in C++. The two testVars however have been created in the script above.
Elements is a table, so I can list all elements, but Avatar.testVar seems to be hidden because Avatar is a LUA_TUSERDATA.
Does anyone have an idea how I can detect variables that have been added to userdata in Lua?
There is no such thing as a "variable stored in userdata", At least, not as far as Lua is concerned. From Lua's perspective, userdata is a giant black box. All Avatar.testVar = 5 does is call the metamethod __newindex in Avatar with the string testVar and the new value 15. How your C++ metamethod (because only C++ code can put metamethods on userdata) interprets this is entirely up to your code.
So it can't be done from Lua. Your code will need to provide debugging hooks. Lua 5.2 allows you to implement the __pairs and __ipairs metamethods, which the pairs and ipairs functions can use to iterate over your values. Outside of that, you're on your own for querying what does and doesn't exist in a userdata.
I used the implicit method for retrieving data objects:
setData = function(segment){
var url = 'https://myFireBase.firebaseio.com/';
var rawData = angularFire(url+segment,$rootScope,'data',{});
rawData.then(function(data){
// sorting and adjusting data, and then broadcasting and/or assinging
}
}
This code is located inside a service that gets called from different locations, by development stages it'll probably be around 100 - 150 so I got out of the controllers and into a service, but now firebase data-binding would obviously over-write the different segments so I turned back to explicit methid, to have the different firebases only sending the data to site instead of data-binding and over-writing each other:
var rawData = angularFireCollection(url+segment);
And right there I discovered why I chose the implicit in the first place: There's an argument for the typeof, i could tell firebase if I'm calling a string, an array, an object etc. I even looked at the angularfire.js and saw that if the argument is not given, if falls back to identifying it as an array by default.
Now, I'm definitely going to move to the explicit method (that is, if no salvation comes with angular2.0), and reconstructing my firebase jsons to fit the array-only policy is not that big of a deal, but surely there's an option to explicitly call objects, or am I missing something?
I'm not totally clear on what the question is - with angularFireCollection, you can certainly retrieve objects just fine. For example, in the bundled chat app (https://github.com/firebase/angularFire/blob/gh-pages/examples/chat/app.js#L5):
$scope.messages = angularFireCollection(new Firebase(url).limit(50));
Each message is stored as an object, with its own unique key as generated by push().
I'm also curious about what problems you found while using the implicit method as your app grew. We're really looking to address problems like these for the next iteration of angularFire!