YetAnotherForum
Welcome Guest Search | Active Topics | Log In | Register

Tables can become unavailable
mingodad2
#1 Posted : Sunday, January 3, 2016 1:33:40 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 1/3/2016(UTC)
Posts: 7
Location: mingodad2

Thanks: 0 times
Was thanked: 0 time(s) in 0 post(s)
Hello !

Be aware of using tables as a general key/values, your program can crash !!!!!!!!

I found that using tables to store arbitrary key/values can make then unavailable, I found this when I was parsing squirrel ".nut" source files to count function calls.

I was storing any found function call on a table and some of then have calls to "rawset","rawget", "rawdelete", "rawin", ...

Code:

local function sumKeys(tbl, key)
{
    local count = tbl.rawget(key, 0);
    tbl.rawset(key, ++count);
}


After setting tbl.rawget("rawget", 1) we can't access the rawget method again unless we call it indirectly like in the example bellow.

Code:


local atable = {};
local table_rawget_fn = atable.rawget;
local table_rawset_fn = atable.rawset;

local function sumKeys(obj, key)
{
    //for direct calls because we want to include table function names as keys
    local count = table_rawget_fn.call(obj, key, 0); //obj.rawget(key, 0);
    table_rawset_fn.call(obj, key, ++count); //obj.rawset(key, ++count);
}


Cheers !
fagiano
#2 Posted : Monday, January 4, 2016 8:52:18 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
That's not a bug, it's a known behavior, arguably not the best. I solve it just like you did. We could come out with an alternative syntax that directly addresses the "default delegate" of the table. I'm open to ideas.

ciao
Alberto
Follow me on Twitter @squirrellang
mingodad2
#3 Posted : Tuesday, January 5, 2016 12:05:31 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 1/3/2016(UTC)
Posts: 7
Location: mingodad2

Thanks: 0 times
Was thanked: 0 time(s) in 0 post(s)
That is what I did now in SquiLu for now (the name maybe can be different):

Code:

/////////////////////////////////////////////////////////////////
//TABLE BASE FUNCTIONS

static SQRESULT bf_table_rawdelete(HSQUIRRELVM v)
{
    if(SQ_FAILED(sq_rawdeleteslot(v,2,SQTrue)))
        return SQ_ERROR;
    return 1;
}


static SQRESULT bf_table_rawexists(HSQUIRRELVM v)
{
    sq_pushbool(v, sq_rawexists(v,-2));
    return 1;
}

static SQRESULT bf_table_rawset(HSQUIRRELVM v)
{
    return sq_rawset(v,-3);
}

static SQRESULT bf_table_rawget(HSQUIRRELVM v)
{
    switch(sq_gettop(v)){
        case 3: return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR;break;
        case 4: {
            sq_push(v, 3); //copy key to top
            sq_rawget(v,-4); //if it fail pop the key and default value is on top
            return 1;
        }
        break;
    }
    return sq_throwerror(v, _SC("invalid number of parameters"));
}

static SQRESULT bf_table_clear(HSQUIRRELVM v)
{
    return sq_clear(v,-1);
}

static SQRESULT bf_table_len(HSQUIRRELVM v)
{
    v->Push(SQInteger(sq_getsize(v,2)));
    return 1;
}

static SQRegFunction base_funcs[]={
    //generic
        ...
    {_SC("table_rawget"),bf_table_rawget,-3, _SC(".t.")},
    {_SC("table_rawset"),bf_table_rawset,4, _SC(".t..")},
    {_SC("table_rawdelete"),bf_table_rawdelete,3, _SC(".t.")},
    {_SC("table_rawin"),bf_table_rawexists,3, _SC(".t.")},
    {_SC("table_len"),bf_table_len,2, _SC(".t")},
    {_SC("table_clear"),bf_table_clear,2, _SC(".t")},
    {0,0}
};


Cheers !
fagiano
#4 Posted : Tuesday, January 5, 2016 1:00:35 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
Yes, that would be a fair solution. I wonder if we can find a syntactic sugar to explicitly address the default delegate.

Alberto
Follow me on Twitter @squirrellang
absence
#5 Posted : Tuesday, January 5, 2016 3:04:41 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 8/23/2014(UTC)
Posts: 109
Man
Location: Northern Germany & Lincolnshire, U.K.

Thanks: 1 times
Was thanked: 10 time(s) in 10 post(s)
fagiano wrote:
Yes, that would be a fair solution. I wonder if we can find a syntactic sugar to explicitly address the default delegate.

Alberto


a double colon AFTER an object maybe? (I know it's ambiguous)
table.slot //normal
table::slot //delegate only and optionally also
table.:slot //raw only

(note this makes ::::slot valid, also ::.:, but is inconsistent to ::slot which then should be ::.slot)

Some other ideas:
table->slot ( mismatching c++ syntax though. Big dislike)
slot via table (delegate only), optionally also
slot of table (raw), and maybe even
slot from table (normal access like table.slot)

I'd like the last ones. Though I'm not too bothered by the whole issue
mingodad2
#6 Posted : Tuesday, January 5, 2016 11:33:15 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 1/3/2016(UTC)
Posts: 7
Location: mingodad2

Thanks: 0 times
Was thanked: 0 time(s) in 0 post(s)
I didn't thought about the possibility of a syntatic sugar, but now that you mention in c++ "::" is used for access the global scope and also for static class/struct member functions, squirrel already use "::" to access the global environment so maybe something like this could also be done:
Code:

local atable = {};

local function sumKeys(obj, key)
{
    //for direct calls because we want to include table function names as keys
    local count = obj::rawget(key, 0); //obj.rawget(key, 0);
    obj::rawset(key, ++count); //obj.rawset(key, ++count);
}


But it'll cause confusion for c++ programmers and squirrel is strong on c++ similarity so probably we need another way.
mingodad2
#7 Posted : Wednesday, January 6, 2016 9:55:04 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 1/3/2016(UTC)
Posts: 7
Location: mingodad2

Thanks: 0 times
Was thanked: 0 time(s) in 0 post(s)
Another possibility also is to to have a way to set a table to be a rawtable so it'll never try delegation and can accept any key, to manipulate the rawtable we should use the indirect metamethod call or syntatic sugar:
Code:

local atable = {}; //or local atable = rawtable({});
atable.setraw(); //option to make a table become a rawtable

local function sumKeys(obj, key)
{
    //assume obj is a rawtable;
    local count = obj::rawget(key, 0); //obj.rawget(key, 0);
    obj[key] = ++count;
}
fagiano
#8 Posted : Wednesday, January 6, 2016 1:23:45 PM(UTC)
Rank: Advanced Member

Groups: Registered, Administrators
Joined: 6/11/2005(UTC)
Posts: 1,056

Thanks: 0 times
Was thanked: 78 time(s) in 60 post(s)
I think the :: operator is not an option because it already has a well defined meaning and it would be quite confusing for C++ developers.
I'm not sure I undestand what a "rawtable" is. Is it a table that doesn't fall back to a built-in delegate?
At the moment I think the Squilu approach to have a table_rawget table_rawset is my favorite.

I almost think the solution could be to expose rawset() rawget() rawdelete() clear() rawin() and len() as builtin-globals and make them work also for array,instances etc... (for the one that apply).

Alberto
Follow me on Twitter @squirrellang
Users browsing this topic
Guest (2)
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Clean Slate theme by Jaben Cargman (Tiny Gecko)
Powered by YAF 1.9.4 | YAF © 2003-2010, Yet Another Forum.NET
This page was generated in 0.090 seconds.