"Sputnik" help  
Sputnik Help
Language Reference - Datatypes - Calbacks

Callbacks

There are multiple kinds of callbacks in Sputnik such as User Variable Functions and Code Blocks to name a couple.

You use one of these callback types in various functions in Sputnik such as Walk and others.

An anonymous statement:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $a <=> $b);
printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Bare in mind with an anonymous statement if it resolves to binary or a string the function could fail entirely since thats expecting bytecode and source code (shown below) to avoid this issue you can encase the statement with @( ) like so:

my $numbers = array("5", "2", "8", "1", "9", "3");
usort($numbers, @($a == "5" ? "1" : "-1"));
printr $numbers;
// PRINTS
// Array
// (
//     [0] => 3
//     [1] => 9
//     [2] => 1
//     [3] => 8
//     [4] => 2
//     [5] => 5
// )
Without the @( ) enclosure you would have to resort to using an anonymous function or code block.

An anonymous statement can be fairly complext:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $a > 5 ? $a <=> $b : $b <=> $a);
printr $numbers;

// PRINTS
// Array
// (
//     [0] => 5
//     [1] => 2
//     [2] => 8
//     [3] => 1
//     [4] => 9
//     [5] => 3
// )

An anonymous statement can be really complex:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $a == $b ? 0 : ($a < $b ? -1 : 1));
printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

An anonymous function:

my $numbers = array(5, 2, 8, 1, 9, 3);

usort($numbers, function ($a, $b)
{
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
});

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have a named function:

my $numbers = array(5, 2, 8, 1, 9, 3);

function NrSorter($a, $b)
{
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
}

usort($numbers, &NrSorter);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

That required a function ref to use hence the & on function name in the usort.

Next we have the code block otherwise known as anonymous code:

my $numbers = array(5, 2, 8, 1, 9, 3);

usort($numbers, 
{{
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
}});

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have the executing code block otherwise known as anonymous code this differs from the one above in that it wants to executes right away and not be saved to variables but when used in callback context it will work the same as the above:

my $numbers = array(5, 2, 8, 1, 9, 3);

usort($numbers, 
@{{
    say "if ($a == $b)";
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
}});

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have the function call:

my $numbers = array(5, 2, 8, 1, 9, 3);

function NrSorter($a, $b)
{
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
}

usort($numbers, NrSorter());

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

It will ignore any arguments placed in the call since its only using it as a reference.

Next is the string which will be parsed as source code and executed:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort
($numbers, " if (\$a == \$b)" " return 0;" " else if (\$a < \$b)" " return -1;" " else" " return 1;" ); printr $numbers; // PRINTS // Array // ( // [0] => 1 // [1] => 2 // [2] => 3 // [3] => 5 // [4] => 8 // [5] => 9 // )

Next we have precompiled code:

my $numbers = array(5, 2, 8, 1, 9, 3);
my $code = CodeCompile(
    "    if (\$a == \$b)"
    "        return 0;"
    "    else if (\$a < \$b)"
    "        return -1;"
    "    else"
    "        return 1;"
);
usort($numbers, $code);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

We can use the heredoc system for making the source version howeer:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers,
    q<<EOT
        if ($a == $b)
            return 0;
        else if ($a < $b)
            return -1;
        else
            return 1;
    EOT
);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Heres the precompiled version using the heredoc system:

my $numbers = array(5, 2, 8, 1, 9, 3);
my $code = CodeCompile(
    q<<EOT
        if ($a == $b)
            return 0;
        else if ($a < $b)
            return -1;
        else
            return 1;
    EOT
);
usort($numbers, $code);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have an anonymous function variable:

my $fn = function ($a, $b)
        {
            if ($a == $b)
                return 0;
            else if ($a < $b)
                return -1;
            else
                return 1;
        };

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $fn);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have a function variable of a named function:

function NrSorter($a, $b)
{
    if ($a == $b)
        return 0;
    else if ($a < $b)
        return -1;
    else
        return 1;
}

my $fn = &NrSorter;

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $fn);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next we have a single statement similar to a code block but only a single statement:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $a <=> $b);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Of course it can be a large single statement:

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, ($a == $b) ? 0 : (($a < $b) ? -1 : 1));

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next is class function reference:

Class Cat
{
    function NrSorter($a, $b)
    {
        if ($a == $b)
            return 0;
        else if ($a < $b)
            return -1;
        else
            return 1;
    }
}

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, &Cat:NrSorter);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Next is class function variable:

Class Cat
{
    function NrSorter($a, $b)
    {
        if ($a == $b)
            return 0;
        else if ($a < $b)
            return -1;
        else
            return 1;
    }
}

my $fn = &Cat:NrSorter;

my $numbers = array(5, 2, 8, 1, 9, 3);
usort($numbers, $fn);

printr $numbers;

// PRINTS
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 5
//     [4] => 8
//     [5] => 9
// )

Due to the fact that a string will be parsed as source code this can be a problem if you wish to use a statement that resolves to a string take this for example:

my $a = q(CAT DOG FOX);
my $mapped = map(IsNullOrEmpty(lc($value)) ? "" : lc($value), @MapNone, Words($a));
printr $mapped;

// PRINTS
// Exception (FunctionWrongParamCount):
// map() Failed to parse source:
// Error type: 'Preprocessor Error'
// Object reference not set to an instance of an object.Source name: 'Main.spk'

Notice the immediate crash? You would think that having the

IsNullOrEmpty(lc($value)) ? "" : lc($value)

Should work just fine and if we was dealing with integers it would be fine however since these are strings it wants to parse it like above so basically it is trying to do this

usort($numbers,
    "    if (\$a == \$b)"
    "        return 0;"
    "    else if (\$a < \$b)"
    "        return -1;"
    "    else"
    "        return 1;"
);

So how do make use the statements that resolve to a string but without resolving the statements to the string and trying to parse it? We can use the @( ) which is similar to ( ) but with the added benefit of telling Sputnik to take the stuff inside it as a statement instead of trying to resolve it.

Here it how we fix the above code:

my $a = q(CAT DOG FOX);
my $mapped = map(@(IsNullOrEmpty(lc($value)) ? "" : lc($value)), @MapNone, Words($a));
printr $mapped;

// PRINTS
// Array
// (
//     [0] => cat
//     [1] => dog
//     [2] => fox
// )
Now Sputnik knows how to handle this statement properly. Of course if you are using a {{ }} code block this is not so important as demonstrated:
my $a = q(CAT DOG FOX);
my $mapped = map({{ return IsNullOrEmpty(lc($value)) ? "" : lc($value); }}, @MapNone, Words($a));
printr $mapped;

// PRINTS
// Array
// (
//     [0] => cat
//     [1] => dog
//     [2] => fox
// )
The downside of course of the {{ }} is the need for a return statement and a ; semi colon thus the @( ) if string (and nothing otherwise) is easier to type and read.

That should cover anything useful of course there may be edge cases that can be done as well.


Contact
Cheryl (uberfox@hotmail.com)
Homepage
http://ubersoft.org