Jump to: main text

Structure examples from Inline::SLang

The following code and examples can be found in the Inline::SLang distribution available from CPAN. The output was created using version 1.00 of the module together with version 1.4.9 of the S-Lang library.

S-Lang structures are converted to hash references in Perl, as shown below. The datatypes example page may also be useful. The support for structures is described in the Inline::SLang::Struct documentation that comes with the module.

Converting structures



Actually, structures are not converted to a hash reference but to a Perl object which behaves like it is a reference to a hash array. The differences to an actual hash array are:

  1. The order of the keys - as returned by foreach, each, keys, ... - is not random but matches the order of the fields in the S-Lang structure.
  2. Keys can not be added to, or removed from, the object.

In most cases you should not need to worry about these differences.

use strict;
use Inline 'SLang';

my $s = get_struct("foo");
print "get_struct() returned a $s - and ref(\$s) = " . ref($s) . "\n\n";
print "Structure contents:\n";

# you can treat $s as a reference to a hash array in most respects, except:
# - the order of the keys in the array matches that of the
#   original S-Lang structure
#
while ( my ( $key, $value ) = each %{$s} ) {
  print "  key $key\t has a value of $value\n";
}
print "\n";

$$s{afield} = 'a changed field value';
print "Key afield now has a value of [$$s{afield}]\n";

__END__
__SLang__

define get_struct(x) {
  variable out = struct { xfield, afield };
  out.xfield = x;
  out.afield = strlen(x);
  return out;
}

If the above is run then it will produce the following output.

get_struct() returned a Struct_Type - and ref($s) = Struct_Type

Structure contents:
  key xfield	 has a value of foo
  key afield	 has a value of 3

Key afield now has a value of [a changed field value]

If you try to access (read or write) a field that does not exist then the Perl code will croak with an error message. As an example, if the previous code had included:

print "Key x has a value of [$$s{x}]\n";

then the program would have terminated with the error

Error: field 'x' does not exist in this Struct_Type structure

It is analogous to S-Lang's Invalid Parameter: struct has no field named x error message.

If you are wondering how "named" structures - i.e. those created by S-Lang's typedef struct { ... } ... statement - are handled, then the answer is that they are also converted to an object which can be treated as a hash reference. This object is a subclass of the Perl Struct_Type class and has a name that matches that given to it in the typedef statement.

To illustrate this we repeat the above code but this time using a typedef-ed structure.

use strict;
use Inline 'SLang';

my $s = get_struct("foo");
print "get_struct() returned a $s - and ref(\$s) = " . ref($s) . "\n\n";
print "Structure contents:\n";
while ( my ( $key, $value ) = each %{$s} ) {
  print "  key $key\t has a value of $value\n";
}
print "\n";
$$s{afield} = 'a changed field value';
print "Key afield now has a value of [$$s{afield}]\n";

__END__
__SLang__

typedef struct { xfield, afield } Example_Struct;
define get_struct(x) {
  variable out = @Example_Struct;
  out.xfield = x;
  out.afield = strlen(x);
  return out;
}

which produces:

get_struct() returned a Example_Struct - and ref($s) = Example_Struct

Structure contents:
  key xfield	 has a value of foo
  key afield	 has a value of 3

Key afield now has a value of [a changed field value]

Using "simple" structures

use Inline 'SLang' => <<'EOS';
variable runtime = time();
typedef struct { x, time } xTime_Struct;
define ret1(x) {
  variable y = struct { x, time };
  y.x    = x;
  y.time = runtime;
  return y;
}
define ret2(x) {
  variable y = @xTime_Struct;
  y.x    = x;
  y.time = runtime;
  return y;
}
EOS

# first with a normal structure
my $s1 = ret1( "struct example" );
print  "ret1() returned a $s1\n";
printf "Is it a structure? [%d]\n", $s1->is_struct_type;
printf "With keys/fields [ %s ]\n",
  join( ", ", keys(%$s1) );
print  " s.x    = $$s1{x}\n";
print  " s.time = $$s1{time}\n";

# and then with a "named" structure
my $s2 = ret2( "named struct example" );
print  "ret2() returned a $s2\n";
printf "Is it a structure? [%d]\n", $s2->is_struct_type;
  printf "With keys/fields [ %s ]\n",
  join( ", ", keys(%$s2) );
print  " s.x    = $$s2{x}\n";
print  " s.time = $$s2{time}\n";

which, when run, produces

ret1() returned a Struct_Type
Is it a structure? [1]
With keys/fields [ x, time ]
 s.x    = struct example
 s.time = Sun Jan  9 18:51:38 2005
ret2() returned a xTime_Struct
Is it a structure? [1]
With keys/fields [ x, time ]
 s.x    = named struct example
 s.time = Sun Jan  9 18:51:38 2005

Using "named" structures

use Inline 'SLang' => <<'EOS';
typedef struct { x, foo } My_Struct;
define is_okay(x) {
  if ( typeof(x) != My_Struct ) {
    vmessage("You sent me a %S", typeof(x));
    return;
  }
  vmessage( "My_Struct field x   = %S", x.x );
  vmessage( "My_Struct field foo = %S", x.foo );
}
EOS

my $s = My_Struct->new();
$$s{x}   = 1;
$$s{foo} = "foo foo";
is_okay( $s );

which, when run, produces

My_Struct field x   = 1
My_Struct field foo = foo foo