Line Numbering Utility in C# and Java


Objective

To compare and contrast C# and Java, using a Unix style utility for numbering source codes.

Target Audience

Java programmers wanting to familiarize with C#.

Summary

This is the first of the series of programs I wish to write to help myself get a handle on C#. This series should also help my peer Java programmers to get a few insights of C#.

Overview

The LineNum  is a line numbering utility I wrote to help me add line numbers in source codes, accompanying the articles I plan to write. The Java version of this utility is poratble across diffrent operating systems like Linux and Solaris. Though C# and the .NET framework are theoritically platform independent, but as of now I do not know how to run it on Linux or Solaris.

The line numbered source codes of Java and C# are provided in Appendix A and B, respectively. You might want to spend some time, at this point, to glance through the source codes.

Some of the diffrences you will note is that the method names in C#, conventionally begin with an upper case. It is not illegal in C# to begin a method name with lower case, neither it is illegal in Java to begin a method name with uppercase character. These are however, matter of conventions.

C# have many new syntax and semantic structures, these I have avoided to use in this example.

I have not used get and set syntax of C# to define properties to keep the code comparison simple.

Design

The LineNum is a simple Unix sytle utility. It has a fine grain structure, that is, the classes and methods have  been isolated functionality, even to the extent that some methods are one line long. The fine grain designs often sacrifice speed efficiencies in favour of reusability and source readibility.

This utility has a two pass design. The first pass calculates the number of lines, hence the maximum padding zeros required. The second pass prints the zero padded line numbered  input source files, to the standard output device.

Diffrences & Similes

To aid comparison between Java and C# versions of the program, I have kept the design, algorithm, and as far as possible, the method names similar.

The C# is more object oriented, in the sense that you can even use methods in atomic types like integers, see line number 72 of the LineNum.cs listing in Appendix B. the string is an alias for System.String of C# API. Java also provides a special treatment to String objects.To accomodate strings, the Java language designers even flouted their own rule of not allowing operator overloading.

The diffrences between LineNum.java and LineNum.cs are few and suttle. Given below are the names and line numbers of the classes used in implementing the utility.

Class Name C# Lines Java Lines Notes
LineNum 54 to 84 56 to 85 The Main util class, having all static methods.
Padder 86 to 108 90 to 110 Helper Class to pad zero to line numbers.
LineCount 110 to 129 115 to 134 Helper Class to find maximum lines in the file.

The method maps between Java and C#, used in the LineNum utility,  are given below.

Java Methods C# Methods Notes
System.exit Environment.Exit Static method to exit the programs with a return value.
BufferedReader StreamReader A reader class containing ReadLine method.
StringBuffer StringBuilder String builder class
System.out.println System.Console.WriteLine printf subset of 'C' method.
import using syntax for including packages or namespaces.
package namespace disambiguates the classes and separates them.
"hello".length()  "hello".Length String method length is implemented as property in C#

Conclusion

C# are Java are similar; Yet, as of now, Java has number of advantages over C#. The first is the portability and availability of Java on most of the popular platforms. However, C# has all the advantages of Visual J++, and may be useful for Java programmers to view it as next generation J++.

C# also have some cool syntax and semantics introduced. And as noted above, it is more object oriented in treatment of basic types by char and int.

However, in spite of the claim by Microsoft that C# is a direct descendent of C++, I feel it is more closer to Java than C++, since Java too was derived from C++. The most missed features of C++ in Java are missing in C# too. Namely the features of multiple inheritance and generic typing called templates are missing in C#.

Just a thought that the '#' character of C# could have been inspired by shifting the second '+' symbol of J++ a little down and telescoping it with the first '+' symbol!

Appendix

Sorry for lack of comments in the source codes. However, I tried to keep the method names  friendly. I also apologize for the rather longish license, can't help it.

Disclaimer

The source codes listed here are for explaining and analyzing the underlying designs only. No warranty claims are made by the author, they may contain bugs or by using them commercially you might be violating copyrights or patents. You may use the ideas and codes presented here at your own risk.

Appendix A

This appendix lists the source code of LineNum.java. I wrote this Unix style utility for generating line numbers for the source codes to be included in programmer's introspection articles and peer review studies.
The source code listings exhibited here, including this one, make use of this utility to generate line numbers.

The file LineNum.java contains three classes, the first one is the class LineNum [lines: 56 to 86] itself. It is a two pass line numbering utility.

It is a utility design pattern class, containing all static methods. The design is finely granuled in terms of functionality, that is each logical function is isolated either in a static method or an independent helper class.

The static method main [lines: 59 to 70] , of the LineNum class, is called by the loader, which in turn opens the source input file to generate the line numbered output, in the example given below it numbers it's own source code!

Using the helper class LineCount [lines: 115 to 134] and the static method maxPadCount [lines: 74 to 75], the utility calculates the maximum padding required. Thereafter, in the second pass, it uses the static method numGen [lines: 78 to 85] to generate the line numbered text to standard output. The numGen static method uses the helper class Padder [lines: 90 to 110] to generate the zero padded line numbers.

To Compile

javac LineNum.java

To Execute

java LineNum LineNum.java > out.txt

Listing of LineNum.java follows:

001 /**
002 *
003 * @author Ashish Banerjee , 5-may-2001
004
*/
005
/*
006 (c) Osprey Software Technology P. Ltd., 2001, All rights reserved.
007 http://www.ospreyindia.com
008
===========================================================================
009 The Osprey Open Source Software License, Version 1.1
010 (Adapted from Apache Software License, V 1.1 [http://www.apache.org])
011
===========================================================================
012
013 Redistribution and use in source and binary forms, with or without modifica-
014 tion, are permitted provided that the following conditions are met:
015
016 1. Redistributions of source code must retain the above copyright notice,
017 this list of conditions and the following disclaimer.
018
019 2. Redistributions in binary form must reproduce the above copyright notice,
020 this list of conditions and the following disclaimer in the documentation
021 and/or other materials provided with the distribution.
022
023 3. The end-user documentation included with the redistribution, if any, must
024 include the following acknowledgment: "This product includes software
025 developed by the Osprey Software Technology P. Ltd. http://www.ospreyindia.com/)."
026 Alternately, this acknowledgment may appear in the software itself, if
027 and wherever such third-party acknowledgments normally appear.
028
029 4. The names "Osprey" and "Osprey Software Technology" must not be used to
030 endorse or promote products derived from this software without prior
031 written permission. For written permission, please contact
032 [email protected].
033
034 5. Products derived from this software may not be called "Osprey", nor may
035 "Osprey" appear in their name, without prior written permission of the
036 Osprey Software Technology.
037
038 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
039 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
040 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
041 OSPREY SOFTWARE TECHNOLOGY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
042 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
043 DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
044 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
045 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
047 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048 */
049
050 import java.io.*;
051
052
/**
053 * Util class with all static methods, it generates line numbers to source
054 * files.
055
*/
056 public class LineNum {
057
private LineNum() {} // no instance allowd
058
059
public static void main(String args[]) throws Exception {
060
if(args.length != 1) {
061 System.
out.println("java LineNum <java-src-file>");
062 System.exit(1);
063 }
064 LineCount cnt =
new LineCount(args[0]);
065
int max = maxPadCount(cnt.getLines());
066
067 BufferedReader rdr =
new BufferedReader(new FileReader(args[0]));
068 numGen(max, rdr);
069 rdr.close();
070 }
071
/**
072 * @return maximum padding digits
073
*/
074 public static int maxPadCount(int lines) {
075
return String.valueOf(lines).length();
076 }
077
/** generates line numbers and outputs to standard out (stdio)*/
078 public static void numGen(int max,BufferedReader inr) throws IOException {
079 String ln;
080 Padder pad =
new Padder('0', max);
081
int cnt = 0;
082
while((ln = inr.readLine()) != null)
083 System.
out.println((pad.pad(++cnt)+" "+ln));
084 }
085 }
086
087
/**
088 * Simple util class to pad zero.
089
*/
090 class Padder {
091
public Padder(char padChar, int maxPad) {
092
this.maxPad = maxPad;
093 StringBuffer buf =
new StringBuffer(maxPad);
094
for(int i=0; i < maxPad;i++)
095 buf.append(padChar);
096 pads = buf.toString();
097 }
098
public String pad(int inp) {
099
return pad(String.valueOf(inp));
100 }
101
public String pad(String inp) {
102 String ret = inp;
103
if((inp != null) && (inp.length() < maxPad))
104 ret = pads.substring(0,(maxPad - inp.length())) + inp;
105
106
return ret;
107 }
108
private int maxPad;
109
private String pads;
110 }
111
112
/**
113 * Opens the file and gets max lines
114
*/
115 class LineCount {
116
public LineCount(String fileName) {
117 fname = fileName;
118 }
119
/**
120 * @return the number of lines in the file.
121
*/
122 public int getLines() throws IOException {
123 BufferedReader rdr =
new BufferedReader(new FileReader(fname));
124
int ret = 0;
125
while(rdr.readLine() != null)
126 ret++;
127 rdr.close();
128
129
return ret;
130 }
131
132
private String fname;
133
134 }

Appendix B

Please refer to the LineNum.java for explainantion of the source code.
I have .NET SDK installed in one of my computers at home, which has Windows 98 system. I prefer to use the console prompt to compile, this creates lesser confusion in my mind while using Linux for Java. As of now, I do not know of a  C# compiler being available on Linux or Solaris. Java however works on all the three OS, I work on!

Be sure to execute corvars.bat before using the Microsoft C# compiler, called csc.exe. Both these programs are located in the bin directory of the .NET SDK.

To Compile 

csc LineNum.cs

The above command compiles the LineNum.cs and produces an executable file called LineNum.exe

To Execute

LineNum LineNum.cs > out.txt

The out.txt file will contain the line numbered source file.

The Listing of LineNum.cs follows:

001 /**
002 *
003 * @author Ashish Banerjee , 5-may-2001
004
*/
005 /*
006 (c) Osprey Software Technology P. Ltd., 2001, All rights reserved.
007 http://www.ospreyindia.com
008
===========================================================================
009 The Osprey Open Source Software License, Version 1.1
010 (Adapted from Apache Software License, V 1.1 [http://www.apache.org])
011
===========================================================================
012
013 Redistribution and use in source and binary forms, with or without modifica-
014 tion, are permitted provided that the following conditions are met:
015
016 1. Redistributions of source code must retain the above copyright notice,
017 this list of conditions and the following disclaimer.
018
019 2. Redistributions in binary form must reproduce the above copyright notice,
020 this list of conditions and the following disclaimer in the documentation
021 and/or other materials provided with the distribution.
022
023 3. The end-user documentation included with the redistribution, if any, must
024 include the following acknowledgment: "This product includes software
025 developed by the Osprey Software Technology P. Ltd. (http://www.ospreyindia.com/)."
026 Alternately, this acknowledgment may appear in the software itself, if
027 and wherever such third-party acknowledgments normally appear.
028
029 4. The names "Osprey" and "Osprey Software Technology" must not be used to
030 endorse or promote products derived from this software without prior
031 written permission. For written permission, please contact
032 [email protected].
033
034 5. Products derived from this software may not be called "Osprey", nor may
035 "Osprey" appear in their name, without prior written permission of the
036 Osprey Software Technology.
037
038 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
039 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
040 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
041 OSPREY SOFTWARE TECHNOLOGY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
042 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
043 DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
044 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
045 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
047 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048 */
049 using System;
050 using System.IO;
051 using System.Text;
052
053 namespace com.ospreyindia.util {
054 public class LineNum {
055 private LineNum() {} // no instance allowd
056
057 public static void Main(string[] args) {
058 if(args.Length != 1) {
059 Console.WriteLine("LineNum <C# source file>");
060 Environment.Exit(1);
061 }
062 LineCount cnt = new LineCount(args[0]);
063 int max = MaxPadCount(cnt.GetLines());
064
065 StreamReader rdr = new StreamReader(new FileStream(args[0], FileMode.Open));
066 NumGen(max, rdr);
067 rdr.Close();
068
069
070 } // END Main
071 public static int MaxPadCount(int lines) {
072 return lines.ToString().Length;
073 }
074 /** generates line numbers and outputs to standard out (stdio)*/
075 public static void NumGen(int max, StreamReader inr) {
076 string ln;
077 Padder pad = new Padder('0', max);
078 int cnt = 0;
079 while((ln = inr.ReadLine()) != null)
080 Console.WriteLine((pad.Pad(++cnt)+" "+ln));
081 }
082
083
084 } // END class LineNum
085
086 public class Padder {
087 public Padder(char padChar, int maxPad) {
088 this.maxPad = maxPad;
089 StringBuilder buf = new StringBuilder(maxPad);
090 for(int i=0; i < maxPad;i++)
091 buf.Append(padChar);
092
093 pads = buf.ToString();
094 }
095 public string Pad(int inp) {
096 return Pad(inp.ToString());
097 }
098 public string Pad(string inp) {
099 string ret = inp;
100 if((inp != null) && (inp.Length < maxPad)) {
101 ret = pads.Substring(0,(maxPad - inp.Length)) + inp;
102 }
103
104 return ret;
105 }
106 private int maxPad;
107 private string pads;
108 } // END class Padder
109
110 public class LineCount {
111 public LineCount(string fileName) {
112 fname = fileName;
113 }
114
115 public int GetLines() {
116 StreamReader rdr = new StreamReader(new FileStream
fname,FileMode.Open));
117 int ret = 0;
118 while(rdr.ReadLine() != null)
119 ret++;
120 rdr.Close();
121
122 return ret;
123 }
124
125 private String fname;
126
127 } // END class LineCount
128
129 } // END namespace


Similar Articles