For an answer to another question, I wanted to load some serialized lua code into a table. The string to be loaded is of this form:
SavedVars = { }
SavedStats = { }
(where each of the {...} might be any Lua expression, including a table constructor with nested data. I'm assuming it is not calling any (global) functions or using global variables.
What I finally want to have is a table of this form:
{ ["SavedVar"] = { }, ["SavedStats"] = { } }
I do not want to have global variables SavedVars afterwards.
How to do this most elegantly?
(I already found a solution, but maybe someone has a better one.)
Here is my solution:
-- loads a string to a table.
-- this executes the string with the environment of a new table, and then
-- returns the table.
--
-- The code in the string should not need any variables it does not declare itself,
-- as these are not available on runtime. It runs in a really empty environment.
function loadTable(data)
local table = {}
local f = assert(loadstring(data))
setfenv(f, table)
f()
return table
end
It loads the data string with loadstring and then uses setfenv to modify the global environment of the function to a new table. Then calling the loaded function once fills this table (instead of the global environment), which we then can return.
Setting the environment to a new table has the effect that the code can't use any global data at all. I think this is a good way to sandbox the code, but if it is not wanted, you could populate the table before or provide it with some metatable (but unset it before returning the table).
This loading function will also work with serialized data produced like in Saving Tables with Cycles.
Related
There is an API provided function, let's call it createBase which returns a table (object). I want to add methods to this table, but I can't just do x = createBase() and then function x:foo() because I have another function similar to createBase, but it's createExtended. It might be easier to explain with the code I have so far:
import api --I don't know how you'd do this in vanilla Lua, I'd use os.loadAPI("api") but that's computercraft specific, I think
Extended = {}
function Extended:foo()
print("foo from extended")
end
function createExtended(params)
x = api.createBase(params)
Extended.__index = x
return Extended --this is obviously wrong: you can't return a class and expect it to be an object
end
Of course, this doesn't work: but I don't know how I might make it work either. Let's assume the table returned by createBase has a function called bar which just prints bar from base. With this test code, the following outputs are given:
e = createExtended()
e.foo() --prints "foo from extended"
e.bar() --nil, therefor error
How can I make this possible, short of defining function x.bar() inside createExtended?
Thanks in advance.
The very simplest way is to attach the method to it directly, instead of using a metatable.
local function extend(super_instance)
super_instance.newMethod = newMethod
return super_instance
end
local function createExtended(...)
return extend(createSuper(...))
end
This will work, unless your superclass uses __newindex (for example, preventing you from writing to unknown properties/methods), or iterates over the keys using pairs or next, since it will now have an additional key.
If for some reason you cannot modify the object, you will instead have to 'wrap' it up.
You could make a new instance which "proxies" all of its methods, properties, and operators to another instance, except that it adds additional fields and methods.
local function extend(super_instance)
local extended_instance = {newMethod = newMethod}
-- and also `__add`, `__mul`, etc as needed
return setmetatable(extended_instance, {__index = super_instance, __newindex = super_instance})
end
local function createExtended(...)
return extend(createSuper(...))
end
This will work for simple classes, but won't work for all uses:
Table iteration like pairs and next won't find the keys from the original table, since they're not actually there. If the superclass inspects the metatable of the object it is given (or if the superclass is actually a userdata), it will also not work, since you'll find the extension metatable instead.
However, many pure-Lua classes will not do those things, so this is still a fairly simple approach that will probably work for you.
You could also do something similar to Go; instead of having a way to 'extend' a class, you simply embed that class as a field and offer convenience to directly calling methods on the wrapping class that just call the methods on the 'extended' class.
This is slightly complicated by how 'methods' work in Lua. You can't tell if a property is a function-that-is-a-property or if it's actually a method. The code below assumes that all of the properties with type(v) == "function" are actually methods, which will usually be true, but may not actually be for your specific case.
In the worst case, you could just manually maintain the list of methods/properties you want to 'proxy', but depending on how many classes you need to proxy and how many properties they have, that could become unwieldy.
local function extend(super_instance)
return setmetatable({
newMethod = newMethod, -- also could be provided via a more complicated __index
}, {
__index = function(self, k)
-- Proxy everything but `newMethod` to `super_instance`.
local super_field = super_instance[k]
if type(super_field) == "function" then
-- Assume the access is for getting a method, since it's a function.
return function(self2, ...)
assert(self == self2) -- assume it's being called like a method
return super_field(super_instance, ...)
end
end
return super_field
end,
-- similar __newindex and __add, etc. if necessary
})
end
local function createExtended(...)
return extend(createSuper(...))
end
How can I set a table that I pass into a function to nil? When I try
local t = {}
function deleteTable(table)
table = nil
end
deleteTable(t)
Nothing happens, t still points to a table value. Is there any way to set the table passed into a function to nil from within the function?
Edit: Not trying to delete the contents of the table, what I wanted was to remove a reference to a table from within a function so that the table would be garbage collected. I misspoke out of ignorance of what I was actually trying to do.
Simply said, you cannot set a table to nil:
A table is a table is a table.
What you can do is setting the variable or slot of a table pointing to said table to something else like nil.
There is no way (outside the debug-api) to refer to local variables, and you would need table and key to refer to a slot in a table.
But even then the table is only garbage-collected if all such references are gone, and not immediately.
Lua does not do manual memory-management, but lazy garbage-collection.
I believe I found a solution. Would this work for what I'm trying to do?
local t = {};
function removeReference(tab)
--do stuff with tab
return nil;
end
t = removeReference(t);
In the above example I could just do t = nil and not use a function, but in my program the function does other things with the table first; I just want it to end in removing the reference. So is this the best solution, or is there a more ideal way?
In swift, in a loop managed by an index value that iterates, I want to create a variable which has the variable name that is a concatenation of "person_" and the current loop index.
So my loop ends up creating variables like:
var person_0 = ...
var person_1 = ...
var person_2 = ...
etc...
I had no luck searching online so am posting here.
Thanks!
One solution is to store all your variables in an array. The indexes for the variables you store in that array will correspond to the index values you're trying to include in the variable name.
Create an instance variable at the top of your view controller:
var people = [WhateverTypePersonIs]()
Then create a loop that will store however many people you want in that instance variable:
for var i = 0; i < someVariable; i++ {
let person = // someValue of type WhateverTypePersonIs
people.append(person)
}
If you ever need to get what would have been "person_2" with the way you were trying to solve your problem, for example, you could access that person using people[2].
In Swift it is not possible to create dynamic variable names. What you are trying to achieve is the typical use case for an Array.
Create an Array and fill it with your person data. Later, you can access the persons via its index:
var persons: [String] = []
// fill the array
for i in 0..<10 {
persons.append("Person \(i)")
}
// access person with index 3 (indexes start with 0 so this is the 4th person)
println(persons[3]) // prints "Person 3"
let name = "person_\(index)"
then add name to a mutable array declared before the loop.
Something like that?
What you are trying to do is not possible in swift. Variable name is just for human being (Especially in a compiled language), which means they are stripped in compilation phase.
BUT if you really really want to do this, code generation tool is the way to go. Find a proper code generation tool, run it in build phase.
I would like to dynamically add fields (or a new columns) to the resulting output row in Kettle.
After spending hours reading through froum posts and he not so well done scripting documentation, I wondered if Stackoverflow would be of any help.
We can use the below steps to generate Dynamic column generation:
calculator
add constants.
Select required fields in table input and assign those values as a set variable and second transformtion level use get variables hop
How are your input values passed to the SQL query? if they are variables then just pass the table input step to a "get variables" step and get your new columns in that way.
Alternatively you can add columns using either calculator or add constants.
Or you could even use the "get system info" step to get commandline args and dates etc.
First, let me give you a code snippet of what I have in a User Defined Java Class step:
private int fieldToHashGeoIndex;
private int fieldToHashHeadIndex;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
Object[] r=getRow();
if (r==null)
{
setOutputDone();
return false;
}
if (first) {
fieldToHashGeoIndex = getInputRowMeta().indexOfValue(getParameter("FIELD_TO_HASH_GEO"));
if (fieldToHashGeoIndex<0) {
throw new KettleException("Field to hash not found in the input row, check parameter 'FIELD_TO_HASH_GEO'!");
}
fieldToHashHeadIndex = getInputRowMeta().indexOfValue(getParameter("FIELD_TO_HASH_HEAD"));
if (fieldToHashHeadIndex<0) {
throw new KettleException("Field to hash not found in the input row, check parameter 'FIELD_TO_HASH_HEAD'!");
}
first=false;
}
Object[] outputRowData = RowDataUtil.resizeArray(r, data.outputRowMeta.size());
int outputIndex = getInputRowMeta().size();
String fieldToHashGeo = getInputRowMeta().getString(r, fieldToHashGeoIndex);
String fieldToHashHead = getInputRowMeta().getString(r, fieldToHashHeadIndex);
outputRowData[outputIndex++] = MurmurHash.hash64(fieldToHashGeo);
outputRowData[outputIndex++] = MurmurHash.hash64(fieldToHashHead);
putRow(data.outputRowMeta, outputRowData);
return true;
}
Now, normally you configure outputRowMeta from the step's config, but maybe you can modify it in the code. This should allow you to specify additional fields in the code.
As an alternative, you could latch on variable fields by defining fixed output fields on to the step like 'field1', 'field2', etc. and tracking the names of the fields elsewhere. You'd probably have to make all the fields of type String and then do your own type adjustments later.
Now that I think of it, though, variable output fields may lead to trouble: you have to be very careful with what you do in later steps to avoid having errors due to type mismatches or missing fields.
I'm just trying to make a simple function that will return all the data from my SQLITE database as an array. But it looks like when my function is returning the array, the SQL statement is actually still executing... so it's empty... Does anyone have a suggestion? Or am I just going about this whole thing wrong.
I know I could just have the event listener functions outside this function, and they could then set the data. But i'm trying to make a AS3 Class that holds all my SQL functions, and It would be nice to have everything for this particular function just in one function, so it can return an array to me.
public function getFavsGamesArray():Array
{
getFavsArraySql.addEventListener(SQLEvent.RESULT, res);
getFavsArraySql.addEventListener(SQLErrorEvent.ERROR, error);
getFavsArraySql.text = "SELECT * FROM favGames";
getFavsArraySql.execute();
var favsArr:Array = new Array();
function res(e:SQLEvent):void
{
trace("sql good!");
favsArr=getFavsArraySql.getResult().data;
}
function error(e:SQLEvent):void
{
trace("sql error!");
}
trace(favsArr);
return favsArr;
}
Assuming I understood your question, Instead of expecting getFavsGamesArray() to actually return the results from an asynchronous event (which it likely never will), consider passing a function (as an argument) to call within your res() function that would then process the data.
In your SQL helper class, we'll call it SQLHelper.as:
private var processResultsFun:Function;
public function getFavsGamesArray(callBackFun:Function):void
{
processResultsFun = callBackFun;
...
} //Do not return array, instead leave it void
function res(e:SQLEvent):void
{
trace("sql good!");
if(processResultsFun != null)
{
processResultsFun(getFavsArraySql.getResult().data);
}
}
In the class(es) that call your SQL helper class:
function processRows(results:Array):void {
//Make sure this function has an Array argument
//By the time this is called you should have some results
}
...
SQLHelper.getFavsGamesArray(processRows);
You can optionally pass an error handling function as well.
Your problem is that your task is asynchronous.
favsArris a temporary variable, and you return its value directly when getFavsGamesArray completes. At that time, the value will always be null, because the listener methods are called only after the SQL statement is complete - which will be at some time in the future.
You need some way to delay everything you are going to do with the return value, until it actually exists.
The best way to do it is to dispatch your own custom event, and add the value as a field to the event object, or to add a listener method outside of your SQL class directly to the SQLStatement - and have it do stuff with event.target.getResult().data. That way you can always be sure the value exists, when processing occurs, and you keep your SQL behavior decoupled from everything on the outside.
I would also strongly encourage you not to declare your event listeners inside functions like this: You can't clean up these listeners after the SQL statements completes!
True: Declaring a function inside a function makes it temporary. That is, it exists only for the scope of your function, and it is garbage collected when it's no longer needed - just like temporary variables. But "it is no longer needed" does not apply if you use it as an event listener! The only reason this works at all is that you don't use weak references - if you did, the functions would be garbage collected before they are even called. Since you don't, the listeners will execute. But then you can't remove them without a reference! They continue to exist, as will the SQL statement, even if you set its references to null - and you've successfully created a memory leak. Not a bad one, probably, but still...
If you really want to encapsulate your SQL behavior, that is a good thing. Just consider moving each SQL statement to a dedicated class, instead of creating one giant SQLHelper, and having your listener methods declared as member functions - it is much easier to prevent memory leaks and side effects, if you keep references to everything, and you can use these in a destroy method to clean up properly.