Chip's Tips for Developers

Contains coding, but not narcotic.

Swapping two variables in Synergy/DE

July 3rd, 2009 9:19:44 am pst by Sterling Camden

Swapping the contents of two variables is a common programming task that should be easy to perform.  In scripting languages of the Perl tradition it’s dead simple, using simultaneous assignment:

Perl:  ($a,$b) = ($b,$a);
Python:  (a,b) = (b,a)
Ruby:  a,b = b,a

Common Lisp has a macro for the purpose:

(rotatef a b)

Most other languages require more than one statement.  For instance, in C (assuming that a and b are integers):

{ int swap = a; a = b; b = swap; }

which isn’t bad – after all, you could define it as a macro (although you’d have to make the type an argument as well if you wanted to support multiple types).

In Synergy/DE, you can’t put it all on one line, so you can’t define it as a macro:


begin
  data swap, int, a
  a = b
  b = swap
end

Well, actually, now you can define it as a macro, by using Let and Progn.  The downloadable code below does just that, in an include file named swap.def.  The following macros are defined therein:

swap(obj1, obj2, type) – swap two objects, casting as type.
swapi(int1, int2) – swap two integers
swapd(dec1, dec2) – swap two decimal values
swapa(a1, a2) – swap two alphanumeric values (or strings)
swapv(var1, var2) – swap two Vars

Note that you can swap different types as long as both the variables and the objects they contain are compatible with the specified type.  The type you specify will be used to cast both operands, so it can either be a common ancestor or one of the objects has to provide an op_Explicit conversion.  In the case of primitives, “type” will specify the type of conversion you want performed, via Var.

The “type” parameter must be enclosed in parentheses, if it is a type.  If parentheses are omitted, type will be treated as a function, method, or macro name, to which will be passed an object parameter (either a Var or some other class).   This gives you a way to insert your own conversion routine if you need it.  Or you can omit type entirely, if both operands are just object variables (@*).

The test routine test_swap.dbl provides some tests, using assertions.  As you can see from the commented out code at the end, the swap macro does not work for properties (including indexer properties).  That’s because Synergy/DE does not return a value from an assignment to a property.  This issue has already been reported as tracker 23837, so hopefully it will be fixed soon.  Because of that limitation, you can’t use these macros to swap elements of an ArrayList.  But I have even bigger plans for extending ArrayList that will include a method for swapping elements, among other things.

UPDATE 2009-09-13: for Synergy/DE 9.3

Posted in SynergyDE | No Comments » RSS 2.0 | Sphere it!

Associative array (hash, dictionary) class for Synergy/DE

March 16th, 2008 1:29:29 pm pst by Sterling Camden

One of the more useful features found in many scripting languages is the concept of an associative array.  It goes by the name of a hash in Perl and Ruby, or a dictionary in Python.  A hash lets you associate key values with data, and later retrieve a datum using its key — often via a syntax similar to an array element reference.  On this lazy Sunday morning it occurred to me that Synergy/DE could benefit from such a facility.

The downloadable code below contains a Hash class that acts as an array of untyped objects with an alphanumeric index.  You can control the case-sensitivity of the key by setting the CaseSensitive property (which defaults to false) before adding the first item.  Because this uses the new Synergy class syntax, it requires at least version 9 of Synergy/DE.

Usage:

myhash = new Hash()
myhash['key'] = anyobject
anyobject = myhash['key']

If a key is not found, then ^null is returned.  Thus, to clear an item, just set its entry to ^null.  This hash does not reclaim any array entries, so it will eventually grow to the size of all keys that have ever been used to store a value.

As you can see in the code, the class uses an internal ArrayList to store the object references, and associates the keys with array indices using the built-in Symbol Table functions in Synergy/DE.  If the Symbol Table API could take objects as associated data then we wouldn’t need this class at all — but it doesn’t.  The Symbol Table API can only take primitive types for data, so we have to introduce this extra layer of reference in order to support objects.

Synergy/DE’s static typing gets in our way in usage as well.  Because the elements are typed as System.Object, client code must cast any returned element to the type expected.  If a primitive type is to be stored in the hash, then it must be cast as an object in order to box it.  Even though you can store a hash as an element of a hash to created nested arrays, you cannot dereference a nested element using a single statement, because you must first store the nested hash element into a variable of type Hash.  And we don’t get any benefit at all from static typing here.  Of course, you could create a derived class of Hash that expects and returns a specific object type.  That would better be a job for generics, which have not yet been implemented in Synergy/DE.  Personally, I’d like to suspend static typing altogether for a class like this, but that’s just the Ruby talking.

UPDATED 3/22/08: Added an iterator and Count property.

UPDATED 7/6/09: Changed the namespace to “ChipsTips”.

UPDATED 9/9/09: Corrected iterator to use base-zero indexing.

Posted in SynergyDE, Wildly popular | 12 Comments » RSS 2.0 | Sphere it!

Debugging Perl scripts on a web server

January 11th, 2006 5:25:06 pm pst by Sterling Camden

If you’ve ever worked on a web server that doesn’t report Perl errors back to the browser, then this script is for you. Not only will it send the errors back to the browser, but also the output of the target script up to the point of failure. All you do is pass the target script as a “script” parameter to cgidebug.pl:

http://www.yoururl.com/cgidebug.pl?script=yourscript.pl

If you need to pass parameters to your script, just add them as parameters to cgidebug.pl:

http://www.yoururl.com/cgidebug.pl?script=yourscript.pl&param1=param1&param2=param2...

Posted in Perl, Web | No Comments » RSS 2.0 | Sphere it!

Better Tag Cloud