GetFullTime without console warning

Started by rww, Jun 20, 2015, 11:56 AM

Previous topic - Next topic

rww

My Version:
function GetFullTime()
{
local time = date(), sec = Fixa(time.sec), min = Fixa(time.min), hr = Fixa(time.hour), day = Fixa(time.day), mon = Fixa(time.month += 1), year = time.year;
return day+"/"+mon+"/"+year+" - "+hr+":"+min+":"+sec;
}

function Fixa(a)
{
if (a < 10) return "0" + a;
return a;
}

@S.L.C Version:
function GetFullTime()
{
    local t = date();
    return ::format(@"%.2d/%.2d/%d - %.2d:%.2d:%.2d", t.day, t.month, t.year, t.hour, t.min, t.sec);
}

Join to Irrelevant Club Discord: https://discord.gg/MsPPZ5uV4X

.

.

rww

GetFullTime is deprecated and may be removed in the future. Please use Squirrel's time() function instead.
I did it for lazy people ...
Join to Irrelevant Club Discord: https://discord.gg/MsPPZ5uV4X

.

Keep in mind that I wasn't back in the day when that was supposed to be used. So let me ask again. What does it do. Where should this be used.
.

DizzasTeR

@S.L.C, Just look at the image in the first post, below the code.

.

#5
Either way. Here's a simplified version:
function GetFullTime()
{
    local t = date();
    return ::format(@"%.2d/%.2d/%d - %.2d:%.2d:%.2d", t.day, t.month, t.year, t.hour, t.min, t.sec);
}

You don't need to make it GetFullTime2(). Using the older name will simply overwrite the existing function and allow the rest of the code think it's the actual deal.
.

rww

#6
Nice ;)

But, what does "::" before "format(..." ?
return ::format(...
Join to Irrelevant Club Discord: https://discord.gg/MsPPZ5uV4X

.

#7
Quote from: rwwpl on Jun 20, 2015, 02:53 PMBut, what does "::" before "format(..." ?

It's just a stupid habit I have. Usually if you work with OOP you might have issues when trying to use global function. Mainly because it'll look for that function inside the table you currently work with and if it's not found it throws an exception.

That :: prefix simply tells the VM to stop looking for that function/index in the current context and go directly into the root table to look for it.

This example should illustrate my point:
{
    local print = function(str)
    {
        print("you got fooled");
    }

    // you'd expect this to print "test string"
    //  but look above. we overwrote the 'print' index
    print("test string");

    // skip the local scope and go directly to the source
    ::print("test string");
}

Just run it as a simple script to see what I mean.

.

Thijn

It's that piece of code going to make an infinite loop? Why isn't the :: needed inside the custom print function?

.

#9
Quote from: Thijn on Jun 20, 2015, 03:22 PMIt's that piece of code going to make an infinite loop?

Having two { /* ... */ } brackets in squirrel works just like in c++. It's like entering a "sub-scope". I use it all the time when I need to work with temporary data that I want to ditch immediately and I don't want to pollute my current scope.

Take working with SQL as an example:
function DoSomeDbStuff()
{
    local result = 32 + 343; // Just to get an idea.

    // Meh...
    print(result);

    // Enter a new scope
    {
        // Different from the above
        local result = QuerySQL(...);

        local my_value = GetSQLColumnData(...);

        if (my_value == 10) print("dayum...");

        FreeSQLQuery(result);

        // Leaving the context so everything is cleaned
    }

    // Still unchanged
    print(result);

    // Enter a new scope
    {
        // Different from the above
        local result = QuerySQL(...);

        // Enter another sub scope
        {
            // Different from the above
            local result = QuerySQL(...);

            local my_value = GetSQLColumnData(...);

            if (my_value == 13) print("dayum...");

            FreeSQLQuery(result);

            // Leaving the context so everything is cleaned
        }

        local my_value = GetSQLColumnData(...);

        if (my_value == 18) print("dayum...");

        FreeSQLQuery(result);

        // Leaving the context so everything is cleaned
    }

    // Still unchanged
    print(result);

    // You get the idea...
}

Quote from: Thijn on Jun 20, 2015, 03:22 PMWhy isn't the :: needed inside the custom print function?

Everything relies on the 'this' environment. The 'this' environment is basically like a table where the VM will look for stuff when needed. Normally when calling a global/free function. The 'this' environment is the root table by default. The 'this' environment is an invisible argument to the function you call. The function expects that and it's the first argument passed. You don't see it but it's there.

Where was I? Ah, yes. A global/free function will have the global table passed as the first argument to any function you call. So, whenever you call a function or simply use a variable whose index can't be found in the current scope. The VM will look for it in the 'this' environment.

Everything in Squirrel are variables. Even functions. As you all know. The name of a function or variable is actually the index it represents in it's parent table (aka. the 'this' environment). When you use that function the VM goes into that table (the 'this' environment) and retrieves it using the specified name as the index to look for.

However, when you call a member function of a class. The 'this' environment is the actual class instance. Which means that the class instance is passed as the first argument to that function without you seeing it. So now, if an index isn't found in the current scope it goes and looks in that 'this' environment which is the class instance and no longer the root table where all the functions reside. And obviously that class instance wont contain print, format etc.

That's where the :: comes into play. It simply says. Don't fallback to the 'this' environment or the current context when looking for this index. Go directly to the root table and look for it there.

If you've ever worked with JSON then I want you to imagine Squirrel exactly like that. Except everything starts from the root table and goes down just like a JSON document would go.

Here's a bunch of examples that demonstrate the concept:
// Some variable in the global scope
//  This index doesn't exist yet
//  Causing it to falback to the default 'this' table
//    (aka the root table) and creates that slot
//  Equivalent of: getroottable().variable <- "...";
variable <- "variable in global scope";

// Some variable in the current scope
//  Equivalent of: this.variable <- "...";
//  'local' means this scope and not the global scope (I know. It's messed up)
local variable = "variable in local scope";

// Let's print the local one
//  We don't have to fallback to the 'this' environment
//    since we overwrote it in the local scope
print(variable);

// Let's print the global one
print(getroottable().variable);
// Also: print(this.variable);
// Or: print(this["variable"]);
// Remember that 'this' is the root table by default

// Now let's play with classes
//  This is actually just a trable
class Dummy1
{
    variable = "variable in instance scope"

    // 'Dummy1' doesn't exist yet
    // Instantiating this in constructor will result in infinite recursion!
    dmy = null

    // 'echo1' will fail if the class doesn't have this index
    function print(s)
    {
        // Fall to the global table
        ::print("From class : " + s);
    }
    // Above function is equivalent of a member variable:
    //  (remember that functions are variables too and they can be copied/referenced under different names)
    //print = ::print

    function echo1()
    {
        // Falls back to the 'this table'
        //  Which means that this class must have a print index
        print(variable);
    }

    function echo2()
    {
        // Now we don't need to fallback to the 'this' table
        local variable = "variable in function scope";
        //  Which means that this class doesn't need a print index
        ::print(variable);
    }
}

// Let's create a dummy instance
// 'dm1' is actually just a table in the curent table
local dm1 = Dummy1();

dm1.dmy = Dummy1(); // Let's see if it explodes

// The dm1 becomes the 'this' environment in both cases
dm1.echo1();
dm1.echo2();

// The above is equivalent of
Dummy1.echo1.call(dm1);
Dummy1.echo2.call(dm1);

// Let's force those member functions to use our scope
//  You should see the values from the global 'variable'
//  Actuaklly you should see the overwrote one
//  Which means the current 'this' is like a layer over the root table
Dummy1.echo1.call(this);

// Copy 'dm1' into another instance in the global table
//  For the purpouse of the next line
dume <- dm1;

// Let's see how that JSON concept looks like
//  Tables, tables, tables!!!
print( this["dume"]["dmy"]["variable"] );
// ^^^ global table has an index 'dume' which is an instance of Dummy1
//  Dummy1 instance has an instance of another Dummy1
//  Dummy1 instances are practically some special tables
//      and we go through them to reach the 'variable' member of the child Dummy1

// Many more examples if you experiment...
.

Thijn

Thanks, was a nice read. I wasn't aware of those separate scopes, can be quite useful some time.