Home | Login | Recent Changes | Search | All Pages | Help

SemiColonsOnTheHeadOfaPin

See AssumptionsAboutLanguages

This page is reserved for arguement examples about the relative merits of different languages.

At the syntax level, How many semi colons can dance on the head of a pin?
;-)
--BobLee 2002.07.21

Comparing languages... There's a good comparison at <http://www.ipd.uka.de/~prechelt/Biblio/jccpprtTR.pdf> While somewhat flawed because some of the programmers were new to the languages, and the problem being implemented didn't require an object oriented design to solve.

Various other comparisons are at <> and Also, <> and <>.

This page compares Java and Smalltalk, by someone who has worked in both languages... It has a good example of the "hoops"...

Smalltalk code to print the contents of a collection forwards and backwards:

|collection|
collection := OrderedCollection with: 'Beer' with: 'Chips' with: 'Dip'.
collection do: [:each | Transcript cr; show: each].
collection reverseDo: [:each | Transcript cr; show: each].

Python (this isn't exactly the same, since it changes the list's order.)

things = ['Beer', 'Chips', 'Dip']
print map(repr, things)
things2 = things
things2.reverse()
print map(repr, things2)

Java code to do the same thing:

import java.util.ArrayList;


List list = new ArrayList();
list.add("Beer");
list.add("Chips");
list.add("Dip");
Iterator it = list.iterator();
while (it.hasNext())
{
String string = (String)it.next();
System.out.println(string);
}
for(int i = list.size() - 1; i>-1; i--)
{
String string = (String)list.get(i);
System.out.println(string);
}

C++ code to do the same thing (I wrote this, haven't tested it. It might need a correction in the reverse-iteration...)

#include <list>
#include <string>
#include <iostream> // declaration of cout
using namespace std;
list<string> list;
list.push_back("Beer");
list.push_back("Chips");
list.push_back("Dip");
for ( list::iterator it = list.begin(); *it != list.end(); ++it )
{
string astring = *it;
cout << astring << endl;
}
for ( list::reverse_iterator it = list.rbegin(); *it != list.rend(); ++it )
{
string astring = *it;
cout << astring << endl;
}

--KeithRay 2002.07.12


Keith, are you using initializers on the smalltalk collection object? If so, in either C++ or Java:

#include "MyList.h" // or import MyList.*
{

MyList theList = new MyList("Beer", "Chips", "Dip");
theList.printForward();
theList.printReverse();

}

Or, bypassing the collection - since we KNOW everything:
C++:
#include <iostream> // declaration of cout
{

cout << "Beer\nChips\nDip\nDip\nChips\nBeer\n";

}
Java:
{

System.out.println("Beer\nChips\nDip\nDip\nChips\nBeer");

}
Smalltal:k

Transcript cr; show: 'Beer'; cr; show: 'Chips'; cr; show: 'Dip'; cr; show: 'Dip'; cr; show: 'Chips'; cr; show: 'Beer'.

But, that's the trouble with apples & oranges. My concerns in languages presume a reasonable amount of structured syntax. The concerns that bite harder are things that trip-up teams or surprise individuals.

For example, what does it take to safely print the content of a collection when multiple threads act on it? What are the synchronizing, threading and sharing/hiding mechanisms? BobLee 2002.07.21


Examples of gotchas:

In C/C++/Objective C the declaration "int a, b, c;" declares three variables, each of type int. The declaration "int * a, b, c;" declares three variables, the first is a pointer to int, the other two are ints. The following code declares in int pointer type... and the three int pointer variables,

typedef int * IntPtr;
IntPtr a, b, c;

The next piece of code "almost" declares an int pointer type, but not really. It actually declares one int pointer variable, and two int variables.

#define INTPTR int *
INTPTR a, b, c;

Java doesn't have pointers, nor #define macros, but otherwise has the same gotcha for array types. "int[] a, b, c;" declares one int array variable and two int variables.

Pascal [still alive as Borland's Delphi] is more verbose but has less tricky syntax. This declares three ints: "var a, b , c : integer;" and this declares three int pointers: "var a , b , c : pointer to integer;"

--KeithRay 2002.07.21


Another version of the C++ example... one that only people knowledgable in the STL would write... Notice how it implements "operator () " ! Blech.

#include "stdafx.h"
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

struct dumpString
{

void operator()(const std::string& text)
{
std::cout<<text<<std::endl;
}

};
int main(int argc, char* argv[])
{

//Get the code into a container
std::string CharArrays[]= { "Beer", "Chips","Dip"};
std::vector<std::string> strings(CharArrays,CharArrays+3);
std::for_each( strings.begin(), strings.end(), dumpString());
std::for_each( strings.rbegin(), strings.rend(), dumpString());
return 0;

}
--KeithRay 2002.07.21


Two implementations in Ruby. Apparently 'p' and 'puts' are both output functions... the second example is probably not putting the output on separate lines.

collection = ["Beer", "Chips", "Dip"]
collection.each {|item| p item}
collection.reverse_each {|item| p item}

things = ['Beer', 'Chips', 'Dip']
puts things.join(',')
puts things.reverse.join(',')

The previous Ruby implementation didn't follow the spec. Here's one that output one word per line.

things = ['Beer', 'Chips', 'Dip']
puts things.join("\n")
puts things.reverse.join("\n")

An implemention in Objective C, using the classes provided by Cocoa / OpenStep / NextStep... object - method invocations go inside [ brackets ]. "@" tells the compiler to make string objects instead of char arrays.

NSArray * array = [ NSArray arrayWithObjects: @"Beer", @"Chips", @"Dip", nil ];
NSEnumerator * forwards = [ array objectEnumerator ];
NSEnumerator * backwards = [ array reverseObjectEnumerator ];
NSString * object;
while (object = [ forwards nextObject ] )
NSLog( object );
while (object = [ backwards nextObject ] )
NSLog( object );

--KeithRay 2002.07.22

More succinct Objective C implementation

NSArray * array = [ NSArray arrayWithObjects: @"Beer", @"Chips", @"Dip", nil ];
[[MPWByteStream Stdout] writeEnumerator:[myArray objectEnumrator] spacer:@"\n"];
[[MPWByteStream Stdout] writeEnumerator:[myArray reverseObjectEnumrator] spacer:@"\n"];


Are we heading for a bout of examples implemented in the most painful language? I might have to dig up RPG or something like that from the past. I recall that there were some horribly obtuse languages, but mercifully I've forgotten them fo the most part.

Perhaps we should perform the example in DOS's .BAT file syntax? Nah... LOGO? Nah... How about MVS JCL: COND=(....) steps to print one line...

--BobLee 2002.07.22


The .NET versions, for what its worth. Both versions use arrays, because the initilization code is easy, but the iteration would work for at least some other collection types.

VB.NET

Dim ShoppingList As String()
ShoppingList = New String() {"Beer", "Chips", "Dip"}
Dim Item As String
For Each Item In ShoppingList
System.Console.WriteLine(Item)
Next
Dim i As Integer
For i = ShoppingList.Length - 1 To 0 Step -1
System.Console.WriteLine(ShoppingList(i))
Next


C#

string[] ShoppingList;
ShoppingList = new string[] {"Beer", "Chips", "Dip"};
foreach(string Item in ShoppingList)
System.Console.WriteLine(Item);
for(int i = ShoppingList.Length - 1; i >= 0; i--)
System.Console.WriteLine(ShoppingList[i]);

I find both C# and VB.NET to be very similar, and question the need for two new languages. (I think VB.NET is closer to C# than it is to the previous Visual Basics.) - ShannonSeverance


LISP

(let ((list '("Beer" "Chips" "Dip")))
           (map nil #'print list)
(map nil #'print (reverse list)))


Lest we forget how many parens can dance on the head of a pin! -- BobLee 2002.07.24
More semicolons can fit on a pin than parens, holding the size of the pin and font constant.

The not causing a lot of nostalgia version, in Commodore 64 Basic V2:

10 SL$(1) = "BEER"
20 SL$(2) = "CHIPS"
30 SL$(3) = "DIP"
40 FOR I = 1 TO 3
50 PRINT SL$(I)
60 NEXT
70 FOR I = 3 TO 1 STEP -1
80 PRINT SL$(I)
90 NEXT

It's all upper case, because that is the way the Commodore displays it. Most painful part of this program, is the emulator duplicates, as closely as possible, the C=64's layout. Ugh.

- ShannonSeverance


2 years on, I just read the 'Blech' comment.

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

template< typename Type >
void dump( const Type& t )
{

cout << t << endl;

}

int main(int argc, char* argv[])
{

//Get the code into a container
string CharArrays[]= { "Beer", "Chips","Dip"};
vector<string> strings(CharArrays,CharArrays+3);
for_each( strings.begin(), strings.end(), dump< string > );
for_each( strings.rbegin(), strings.rend(), dump< string > );
return 0;

}

If you know the language well enough, you can use it elegantly. Notice also that this solution is no longer entirely OO, it uses 'generic programming'.

--HuwLloyd 2004.08.25


Updated: Wednesday, August 25, 2004