Generic swap: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎Standard ML: Added function that works with references)
No edit summary
Line 404: Line 404:
Tuples are immutable in OCaml. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.
Tuples are immutable in OCaml. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.
let swap (x, y) = (y, x)
let swap (x, y) = (y, x)
If the arguments are constrained to be reference values, a swap function is simple:
let swapref x y =
let temp = !x in
x := !y;
y := temp


=={{header|Octave}}==
=={{header|Octave}}==

Revision as of 18:11, 8 May 2009

Task
Generic swap
You are encouraged to solve this task according to the task description, using any language you may know.

Many statically typed languages provide a generic programming capability. In C++ this capability is called templates. In Ada it is called generics. Such generic capabilities are simply the natural approach to programming for dynamically typed languages.

This task asks you to create a generic swap method that can be used for a wide variety of data types. If your solution language is statically typed please describe the way your language provides genericity. (This is actually a simple example of Parametric Polymorphism)

Ada

The generic parameters for an Ada generic procedure are defined in a procedure specification, while the algorithm is defined in a procedure body. The first code snippet is the procedure instantiation. The second code snippet is the procedure body.

generic
   type Swap_Type is private; -- Generic parameter
procedure Generic_Swap(Left : in out Swap_Type; Right : in out Swap_Type);
procedure Generic_Swap(Left : in out Swap_Type; Right : in out Swap_Type) is
   Temp : Swap_Type := Left;
begin
   Left := Right;
   Right := Temp;
end Generic_Swap;

C

This has a restriction that a and b must be the same size. I think you could do better with preprocessor voodoo, but I am not enlightened enough to use it. I'm being cute here, so please don't hate me too much, and if a C guru could check it, I'd appreciate it (I tried it and it worked for me). It won't work for something like a linked list if you want all references to middle nodes to be translated, but it'll swap the heads just fine.

<lang c> void swap(void *a, void *b, size_t size)

 {
   char *ca, *cb;
   int i;
   ca = (char *)a;
   cb = (char *)b;
   for(i=0;i<size;*(ca+i)^=*(cb+i),*(cb+i)^=*(ca+i),*(ca+i)^=*(cb+i),++i);
 }</lang>


You could also do it with a third buffer but then it wouldn't work for extremely large void pointers. It'd be faster to use a larger pointer than char *, but I wanted to keep it simple.

Another maybe better way is to use preprocessor macros and __typeof__ (supported by C89 at least)

<lang c>#define Swap(X,Y) do{ __typeof__ (X) _T = X; X = Y; Y = _T; }while(0)</lang>

Usage examples are:

<lang c>#include <stdio.h>

  1. define Swap(X,Y) do{ __typeof__ (X) _T = X; X = Y; Y = _T; }while(0)

struct test {

 int a, b, c;

};


int main() {

 struct test t = { 1, 2, 3 };
 struct test h = { 4, 5, 6 };
 double alfa = 0.45, omega = 9.98;
 
 struct test *pt = &t;
 struct test *th = &h;
 
 printf("%d %d %d\n", t.a, t.b, t.c );
 Swap(t, h);
 printf("%d %d %d\n", t.a, t.b, t.c );
 printf("%d %d %d\n", h.a, h.b, h.c );
 
 printf("%lf\n", alfa);
 Swap(alfa, omega);
 printf("%lf\n", alfa);
 
 printf("%d\n", pt->a);
 Swap(pt, th);
 printf("%d\n", pt->a);

}</lang>

This is tested with GCC with -std=c89 option.

C++

Generic programming in C++ is provided through templates. Templates in C++ are quite powerful: They form a Turing-complete compile-time sub-language. However, that power isn't needed for swap. Note that the C++ standard library already provides a swap function which contains optimized implementations for standard library types; thus it's advisable to use that instead of a self-written variant like the one below.

While the standard allows to separate declaration and definition of templates into different files using the export keyword, most compilers (including the most used ones) don't implement that. Therefore in practice, templates declared in header files also have to be defined there.

The implementation of the swap function template is straightforward:

template<typename T> void swap(T& left, T& right)
{
  T tmp(left);
  left = right;
  right = tmp;
}

Note that this function requires that the type T has an accessible copy constructor and assignment operator.

C#

Works with: C# version 2.0+

C# 2.0 introduced the concept of generics to the language. Generics are outwardly similar to C++ templates, but are implemented quite differently: generics are maintained generically at runtime rather than being substitued with definite types by the compiler. Generics are intended to promote reusable, efficient, type-safe code, and are used widely throughout the .NET framework and 3rd party libraries, especially in collections. C# generics are less flexible than C++ templates, but are more strongly typed and arguably easier to deal with.

<lang csharp>static void Swap<T>(ref T a, ref T b) {

   T temp = a;
   a = b;
   b = temp;

}</lang>


Clojure

 (defn swap [[a b]] (list b a))

This implementation will always return a list, regardless of whether the input is a vector.

ColdFusion

This is another standard swap.

<cfset temp = a />
<cfset a = b />
<cfset b = temp />

D

The solution for D is quite similar to that for C++:

 void swap(T)(ref T left, ref T right) {
   auto temp = left;
   left = right;
   right = temp;
 }

dc

We use two registers to swap in POSIX dc.

1 2 sa sb la lb f
=2 1

Reverse (r) is a built-in stack command available as a GNU extension for dc.

1 2 r f
=2 1

Common Lisp

(rotatef a b)
(psetq a b b a)

E

(slots)

def swap(&left, &right) {
  def t := left
  left := right
  right := t
}

(functional)

def swap([left, right]) {
  return [right, left]
}

Fortran

Works with: Fortran version 90 and later

<lang fortran> MODULE Genericswap

  IMPLICIT NONE

  INTERFACE Swap
    MODULE PROCEDURE Swapint, Swapreal, Swapstring
  END INTERFACE

CONTAINS

  SUBROUTINE Swapint(a, b)
    INTEGER, INTENT(IN OUT) :: a, b
    INTEGER :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapint

  SUBROUTINE Swapreal(a, b)
    REAL, INTENT(IN OUT) :: a, b
    REAL :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapreal

  SUBROUTINE Swapstring(a, b)
    CHARACTER(*), INTENT(IN OUT) :: a, b
    CHARACTER(len(a)) :: temp
    temp = a ; a = b ; b = temp
  END SUBROUTINE Swapstring
END MODULE Genericswap

PROGRAM EXAMPLE
  USE Genericswap
  IMPLICIT NONE
  INTEGER :: i1 = 1, i2 = 2
  REAL :: r1 = 1.0, r2 = 2.0
  CHARACTER(3) :: s1="abc", s2="xyz"

  CALL Swap(i1, i2)
  CALL Swap(r1, r2)
  CALL Swap(s1, s2)

  WRITE(*,*) i1, i2   ! Prints 2 and 1
  WRITE(*,*) r1, r2   ! Prints 2.0 and 1.0
  WRITE(*,*) s1, s2   ! Prints xyz and abc
END PROGRAM EXAMPLE</lang>

Groovy

Groovy has support for swapping built in:

<lang groovy>(a, b) = [b, a]</lang>

But the task calls for a "generic swap method" to be written, so here it is:

<lang groovy>def swap(a, b) {

   [b, a]

}</lang> This function doesn't mutate anything, but simply returns a new list with the order of the elements switched. It can be used like shown below: <lang groovy>def (x, y) = swap(1, 3) assert x == 3 assert y == 1</lang>

Haskell

Like everything else in Haskell, tuples are immutable. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.

The type signature, the first line, is optional; it may be inferred.

swap :: (a, b) -> (b, a)
swap (x, y) = (y, x)

Icon

Icon provides :=: operator for this.

procedure main()
   local x, y, v
   v := create(1 to 2)
   every (x | y) := @v
   write(x," ",y)
   x :=: y
   write(x," ",y)
end

J

J is dynamically typed so the generic swap has a simple solution: the easiest way to handle this is using the monad 'reverse' |. on a two item array.

   |. 1 2
2 1

   |. 'ab'
ba

   ('ab';5);<'YUIJK';6
+------+---------+
|+--+-+|+-----+-+|
||ab|5|||YUIJK|6||
|+--+-+|+-----+-+|
+------+---------+

   |. ('ab';5);<'YUIJK';6
+---------+------+
|+-----+-+|+--+-+|
||YUIJK|6|||ab|5||
|+-----+-+|+--+-+|
+---------+------+
 
   [ a=:(i.2 3); i.3 4
+-----+---------+
|0 1 2|0 1  2  3|
|3 4 5|4 5  6  7|
|     |8 9 10 11|
+-----+---------+
   |. a
+---------+-----+
|0 1  2  3|0 1 2|
|4 5  6  7|3 4 5|
|8 9 10 11|     |
+---------+-----+

Another possibility is using the dyad 'passive' with verb 'append' in combination with adverb 'insert' acting on a two item array argument:

passive with append:  x ,~ y  <==>  y , x

   ,~/ 1 2 
2 1

   1 2 3; 8 9 7
+-----+-----+
|1 2 3|8 9 7|
+-----+-----+
 
   ,~/ 1 2 3; 8 9 7
+-----+-----+
|8 9 7|1 2 3|
+-----+-----+

Composite data:
    ('ab';5);<'YUIJK';6
+------+---------+
|+--+-+|+-----+-+|
||ab|5|||YUIJK|6||
|+--+-+|+-----+-+|
+------+---------+

    ,~/ ('ab';5);<'YUIJK';6
+---------+------+
|+-----+-+|+--+-+|
||YUIJK|6|||ab|5||
|+-----+-+|+--+-+|
+---------+------+

Java

Works with: Java version 1.5+
class Pair<T> {
    T first;
    T second;
}
public static <T> void swap(Pair<T> p) {
   T temp = p.first;
   p.first = p.second;
   p.second = temp;
}

Mathematica

Mathematica functions are generic by default; however, it has to be told not to evaluate the arguments before executing the function.

swap[a_, b_] := {a, b} = {b, a}
SetAttributes[swap, HoldAll]

MAXScript

swap a b

Metafont

In Metafont, only numeric declarations can be omitted; any other type, must be explicitly given. So our swap, in order to declare and use a proper temporary variable(? in this code), must check the type of the variable passed (we check only for a; if b is of another kind, an error will occur)

<lang metafont>vardef swap(suffix a, b) =

 save ?; string s_;
 if boolean a: boolean ?
   elseif numeric a: numeric ? % this one could be omitted
   elseif pair a: pair ?
   elseif path a: path ?
   elseif pen a: pen ?
   elseif picture a: picture ?
   elseif string a: string ?
   elseif transform a: transform ? fi;
 ? := a; a := b; b := ?

enddef;</lang>

Examples:

<lang metafont>j := 10; i := 5; show j, i; swap(j,i); show j, i;

boolean truth[]; truth1 := true; truth2 := false; show truth1, truth2; swap(truth1,truth2); show truth1, truth2;</lang>

Modula-3

<lang modula3>GENERIC INTERFACE GenericSwap(Elem);

PROCEDURE Swap(VAR left: Elem.T; VAR right: Elem.T);

END GenericSwap.</lang> <lang modula3>GENERIC MODULE GenericSwap(Elem);

PROCEDURE Swap(VAR left: Elem.T; VAR right: Elem.T) =

 VAR temp: Elem.T := left;
 BEGIN
   left := right;
   right := temp;
 END Swap;

BEGIN END GenericSwap.</lang>

Here is an example usage for integers: <lang modula3>INTERFACE IntSwap = GenericSwap(Integer) END IntSwap.</lang> <lang modula3>MODULE IntSwap = GenericSwap(Integer) END IntSwap.</lang> <lang modula3>MODULE Main;

IMPORT IntSwap, IO, Fmt;

VAR left := 10;

   right := 20;

BEGIN

 IO.Put("Left = " & Fmt.Int(left) & "\n");
 IntSwap.Swap(left, right);
 IO.Put("Left = " & Fmt.Int(left) & "\n");

END Main.</lang>

Output:

Left = 10
Left = 20

Nial

Like J

|reverse 1 2
=2 1

OCaml

Tuples are immutable in OCaml. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.

let swap (x, y) = (y, x)

If the arguments are constrained to be reference values, a swap function is simple:

let swapref x y =
  let temp = !x in
    x := !y;
    y := temp

Octave

GNU Octave has no way to pass a value by reference to a function; so to define a swap we must do as follow:

<lang octave>function [a, b] = swap(ia, ib)

 a = ib; b = ia;

endfunction

% testing va = 2; vb = 5; printf("%d %d\n", va, vb); [va, vb] = swap(va, vb); printf("%d %d\n", va, vb);</lang>

Perl

Perl has support for swapping built-in

<lang perl> ($y, $x) = ($x, $y); </lang>

Here's a generic swap routine:

<lang perl>sub swap {@_[0, 1] = @_[1, 0]}</lang>

PHP

<lang php>function swap(&$a, &$b) {

   list($a, $b) = array($b, $a);

}</lang>

Pop11

Swap is easily done via multiple assignment:

(a, b) -> (b, a);

Pop11 is dynamically typed, so the code above is "generic".

Python

Python has support for swapping built in:

<lang python>a, b = b, a</lang>

But the task calls for a "generic swap method" to be written, so here it is:

<lang python>def swap(a, b):

   return b, a</lang>

Note that tuples are immutable in Python. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.

Ruby

Ruby has support for swapping built in:

<lang ruby>a, b = b, a</lang>

But the task calls for a "generic swap method" to be written, so here it is:

<lang ruby>def swap(a, b)

   return b, a

end</lang> This function doesn't mutate anything, but simply returns a new array with the order of the elements switched.

Seed7

A generic template to generate swap functions is defined with:

const proc: generate_swap (in type: aType) is func
  begin

    const proc: swap (inout aType: left, inout aType: right) is func
      local
        var aType: temp is aType.value;
      begin
        temp := left;
        left := right;
        right := temp;
      end func;

  end func;

An instance of a swap function can be generated with:

generate_swap(integer);
generate_swap(string);

A swap function can be called with:

swap(a, b);

Standard ML

Tuples are immutable in Standard ML. This function doesn't mutate anything, but simply returns a new pair with the order of the elements switched.

fun swap (x, y) = (y, x)

If the arguments are constrained to be reference values, a swap function is simple:

fun swapref (x, y) =
    let temp = !x in x := !y; y := temp end

Tcl

Works with: Tcl version 8.5

<lang tcl>proc swap {aName bName} {

   upvar 1 $aName a $bName b
   lassign [list $a $b] b a

}</lang>

Works with: Tcl version 8.4

<lang tcl>proc swap {aName bName} {

   upvar 1 $aName a $bName b
   foreach {b a} [list $a $b] break

}</lang>

<lang tcl>set a 1 set b 2 puts "before\ta=$a\tb=$b" swap a b puts "after\ta=$a\tb=$b"</lang>

Outputs:

before	a=1	b=2
after	a=2	b=1

V

Using the view to shuffle the stack.

[swap [a b : b a] view].
1 2 swap
= 2 1
'hello' 'hi' swap
='hi' 'hello'