Home > Archive > Cobol > February 2007 > Re: My First C# (warning - long post)
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Re: My First C# (warning - long post)
|
|
| andrewmcdonagh 2007-01-31, 9:55 pm |
| On Jan 31, 9:54 pm, "andrewmcdonagh" <andrewmcdon...@gmail.com> wrote:
> On Jan 31, 1:00 am, LX-i <lxi0...@netscape.net> wrote:
>
>
>
>
.....
[color=darkred]
> time for a break....(aka kids playing up... ;-) )
>
> Andrew
Ok, so I downloaded and installed vs2005 express, loaded your class
and started using the 'refactoring -> extract method' right click menu
option....
Here's what I've got so far....(if you paste it into your
vs2005...you'll need to spend a few minutes sorting out the line wraps
that posting it to here causes...)
More tomorrow....
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Text;
namespace CodeStats
{
public class CodeStatistics
{
// Properties (public instance variables)
bool updatedStats = false;
String elementId = "";
int locTotal = 0;
int locExecutable = 0;
int locCommented = 0;
// Private instance variables
protected SqlConnection dbConn;
protected SqlConnection dbHelp;
protected char elementType = ' ';
protected String elementSubType = "";
protected String fileName = "";
protected bool inComment = false;
protected List<String> programID = new List<String>();
protected String[] cobolKeywords =
{"ACCEPT","ACCESS","ACQUIRE","ADD","ADVANCING","AFTER","ALL",
"ALPHABET","ALPHABETIC","ALPHABETIC-LOWER","ALPHABETIC-
UPPER",
"ALPHANUMERIC","ALPHANUMERIC-EDITED","ALSO","ALTER","ALTERNATE",
"AND","ANY","APPLY","ARE","AREA","AREAS","ASCENDING","ASSIGN","AT",
"AUTHOR","BEFORE","BINARY","BINARY-1","BIT","BLANK","BLOCK",
"BOTTOM","BY","BYTE-I18N","CALL","CANCEL","CD","CF","CH",
"CHARACTER","CHARACTERS","CLASS","CLASS-NAME","CLOCK-
UNITS",
"CLOSE","COBOL","CODE","CODE-
SET","COLLATING","COLUMN","COMMA",
"COMMON","COMMON-
STORAGE","COMMUNICATION","COMP","COMP-1",
"COMP-2","COMPUTATIONAL","COMPUTATIONAL-1","COMPUTATIONAL-2",
"COMPUTE","CONFIGURATION","CONTAINS","CONTENT","CONTINUE","CONTROL",
"CONTROLS","CONVERTING","COPY","CORR","CORRESPONDING","COUNT",
"CURRENCY","DATA","DATE","DATE-COMPILED","DATE-
WRITTEN","DAY",
"DAY-OF-WEEK","DE","DEBUG-CONTENTS","DEBUG-ITEM","DEBUG-
LINE",
"DEBUG-NAME","DEBUG-SUB-1","DEBUG-SUB-2","DEBUG-SUB-3",
"DEBUGGING","DECIMAL-POINT","DECLARATIVES","DELETE","DELIMITED",
"DELIMITER","DENSITY","DEPART","DEPENDING","DESCENDING",
"DESTINATION","DETAIL","DISABLE","DISP","DISP-2","DISP-
I18N",
"DISPLAY","DISPLAY-2","DIVIDE","DIVISION","DOWN","DUPLICATE",
"DYNAMIC","EGI","ELSE","EMI","EMPTY","ENABLE","END","END-
ADD",
"END-CALL","END-COMPUTE","END-DELETE","END-DIVIDE","END-EVALUATE",
"END-IF","END-MULTIPLY","END-OF-PAGE","END-PERFORM","END-
READ",
"END-RECEIVE","END-RETURN","END-REWRITE","END-SEARCH","END-STRING",
"END-SUBTRACT","END-UNSTRING","END-
WRITE","ENTER","ENTRY",
"ENVIRONMENT","EOP","EQUAL","ERROR","ESI","EVALUATE","EVERY",
"EXCEPTION","EXDEF","EXEC","EXIT","EXREF","EXTEND","EXTERNAL",
"FALSE","FD","FETCH","FILE","FILE-CONTROL","FILLER","FINAL","FIND",
"FIRST","FOOTING","FOR","FREE","FROM","FUNCTION","GENERATE","GET",
"GIVING","GLOBAL","GO","GREATER","GROUP","HEADING","HIGH-VALUE",
"HIGH-VALUES","I-O","I-O-CONTROL","IDENTIFICATION","IF","IMPART",
"IN","INDEX","INDEXED","INDICATE","INITIAL","INITIALIZE","INPUT",
"INPUT-OUTPUT","INSERT","INSPECT","INSTALLATION","INTO","INVALID",
"INVOKE","IS","JUST","JUSTIFIED","KEEP","KEY","LABEL","LAST",
"LEADING","LEFT","LENGTH","LESS","LIMIT","LIMITS","LINAGE",
"LINAGE-COUNTER","LINE","LINE-COUNTER","LINES","LINKAGE","LOCALE",
"LOCK","LOG","LOW-VALUE","LOW-VALUES","MEMORY","MERGE","MESSAGE",
"MODE","MODE-1","MODE-2","MODE-3","MODE-4","MODIFY","MODULES",
"MOVE","MULTIPLE","MULTIPLY","NATIVE","NEGATIVE","NEXT","NO","NOT",
"NUMBER","NUMERIC","NUMERIC-EDITED","OBJECT-COMPUTER","OCCURS","OF",
"OFF","OMITTED","ON","OPEN","OPTIONAL","OR","ORDER","ORGANIZATION",
"OTHER","OUTPUT","OVERFLOW","OWNER","PACKED-
DECIMAL","PADDING",
"PAGE","PAGE-COUNTER","PERFORM","PF","PH","PIC","PICTURE","PLUS",
"POINTER","POINTS","POSITION","POSITIVE","PRINTING","PRIOR",
"PROCEDURE","PROCEDURES","PROCEED","PROGRAM","PROGRAM-ID","PURGE",
"QUEUE","QUOTE","QUOTES","RANDOM","RANK","RD","READ","RECEIVE",
"RECORD","RECORDING","RECORDS","REDEFINES","REEL","REFERENCE",
"REFERENCES","RELATIVE","RELEASE","REMAINDER","REMOVAL","REMOVE",
"RENAMES","REPLACE","REPLACING","REPORT","REPORTING","REPORTS",
"RERUN","RESERVE","RESET","RETURN","REVERSED","REWIND","REWRITE",
"RF","RH","RIGHT","ROUNDED","RUN","SAME","SD","SEARCH","SECTION",
"SECURITY","SEGMENT","SEGMENT-LIMIT","SELECT","SEND","SENTENCE",
"SEQUENTIAL","SET","SIGN","SIZE","SORT","SORT-
MERGE","SOURCE",
"SOURCE-COMPUTER","SPACE","SPACES","SPECIAL-
NAMES","STANDARD",
"STANDARD-1","STANDARD-2","START","STATUS","STOP","STORE","STRING",
"SUB-QUEUE-1","SUB-QUEUE-2","SUB-
QUEUE-3","SUBTRACT","SUM",
"SUPPRESS","SYMBOLIC","SYNC","SYNCHRONIZED","TABLE","TALLYING",
"TAPE","TERMINAL","TERMINATE","TEST","TEXT","THAN","THEN",
"THROUGH","THRU","TIME","TIMES","TO","TOP","TRAILING","TRUE","TYPE",
"UNIT","UNSTRING","UNTIL","UP","UPON","USAGE","USE","USING","VALUE",
"VALUES","VARYING","WHEN","WITH","WORDS","WORKING-STORAGE","WRITE",
"ZERO","ZEROES","ZEROS","+","-","*","/","**",">","<","=",">=","<="};
// Constuctor for no parameter
public CodeStatistics(String csServerName)
{
openSqlConnection(csServerName);
}
// Constructor for passed Element ID
public CodeStatistics(String csServerName, String
csElementId)
{
openSqlConnection(csServerName);
retrieveElementInfo(csElementId);
}
// Establish the element for this class instance
public void retrieveElementInfo(String reiElementId)
{
// Retrieve the information about the passed program
SqlCommand cmd = new SqlCommand("SELECT element_id,
element_type, element_subtype, server_name "
+ "FROM active_elements "
+ "WHERE element_id = '" + reiElementId.Trim() + "'",
dbConn);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
elementType =
Convert.ToChar(dr["element_type"].ToString().Trim().Substring(0,1));
elementSubType =
dr["element_subtype"].ToString().Trim();
fileName = dr["server_name"].ToString().Trim();
elementId = reiElementId;
}
dr.Close();
dr.Dispose();
}
// Update the statistics for the element ID
public void updateStatistics(String usPath, String
usProcessName)
{
if (File.Exists(usPath + fileName))
{
String textLine = "";
clearOutCrossReferenceTables();
textLine = parseFile(usPath, usProcessName,
textLine);
deleteAnyReferencesToCallsIfTheTargetIsD
efinedInTheProgram();
updateLocInTheCscsDatabase();
}
}
private void updateLocInTheCscsDatabase()
{
// Update LOC in the CSCS database
SqlCommand sc = new SqlCommand("UPDATE Active_Elements "
+ "SET Commented_Lines = " +
locCommented.ToString()
+ ", Executable_Lines = " +
locExecutable.ToString()
+ ", Total_Lines = " + locTotal.ToString()
+ "WHERE Element_ID = '" + elementId + "'", dbConn);
sc.ExecuteNonQuery();
sc.Dispose();
}
private void
deleteAnyReferencesToCallsIfTheTargetIsD
efinedInTheProgram()
{
if (programID.Count > 0)
{ // Delete any references to calls if the target is
defined in the program (i.e., nested subprograms)
SqlCommand scDelete = new SqlCommand();
scDelete.CommandText = "DELETE FROM
sdp_CSCI_CALL_Xref "
+ "WHERE Element_ID = '" + elementId + "' "
+ "AND Call_Name IN ('";
for (int i = 0; i < programID.Count; i++)
{
scDelete.CommandText += programID[i] + "'";
if (i < (programID.Count - 1))
{
scDelete.CommandText += ",'";
}
}
scDelete.CommandText += ")";
scDelete.Connection = dbConn;
scDelete.ExecuteNonQuery();
scDelete.Dispose();
}
}
private String parseFile(String usPath, String usProcessName,
String textLine)
{
StreamReader file = File.OpenText(usPath + fileName);
while (!file.EndOfStream)
{
textLine = file.ReadLine().ToUpper();
if ((elementType != 'P') && (elementType != 'L'))
{
textLine = textLine.Trim();
}
countLine(textLine); // Count this line as a "line of
code"
switch (elementType)
{
case 'P':
case 'L':
textLine = textLine.Replace(",", "
").Replace(".", " ").Trim();
updateProcXref(textLine);
updateRejectXref(textLine, usProcessName);
updateCallXref(textLine);
//updateCull(textLine);
break;
}
}
file.Close();
file.Dispose();
return textLine;
}
private void clearOutCrossReferenceTables()
{
// Depending on the type, clear out the cross-reference
tables
switch (elementType)
{
case 'P':
case 'L':
SqlCommand scDel = new SqlCommand();
scDel.Connection = dbConn;
// Delete item/proc xref
scDel.CommandText = "DELETE FROM Proc_Prog_Xref
WHERE ProgName = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete item/reject xref
scDel.CommandText = "DELETE FROM RejectsXref
WHERE program = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete item/call xref
scDel.CommandText = "DELETE FROM
sdp_CSCI_Call_Xref WHERE Element_ID = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete cull information
scDel.CommandText = "DELETE FROM
sdp_Dbe_Csci_Xref WHERE CSCI = '" + elementId + "'";
scDel.ExecuteNonQuery();
scDel.CommandText = "DELETE FROM
sdp_Dbr_Csci_Xref WHERE CSCI = '" + elementId + "'";
scDel.ExecuteNonQuery();
scDel.Dispose();
break;
}
}
protected void countLine(String clLine)
{
String commentStart = "";
String commentEnd = "";
String commentSingle = "";
// A line is a line...
locTotal++;
if (clLine != "")
{
switch(elementType)
{
case 'P':
case 'L':
lineOfCobolCode(clLine);
break;
case 'G':
linesOfGuiCode(clLine, ref commentStart, ref
commentEnd, ref commentSingle);
break;
case 'R':
linesOfRunstreamsCode(clLine);
break;
case 'Q':
linesOfIquRunstreamsCode(clLine);
break;
default:
// Anything else, a non-blank line is
executable
locExecutable++;
break;
}
}
}
private void linesOfIquRunstreamsCode(String clLine)
{
// IQ/U Runstreams
if (clLine.Substring(0, 1) == ".")
{
locCommented++;
}
else
{
locExecutable++;
}
}
private void linesOfRunstreamsCode(String clLine)
{
// Runstreams
if ((elementSubType == "IPF") && (clLine.Substring(0, 1)
== "@"))
{ // IPF comment character
locCommented++;
}
else
{
if ((elementSubType == "QLP") && (clLine.Substring(0,
1) == "*"))
{ // QLP comment character
locCommented++;
}
else
{ // Apply ECL comment rules
if ((clLine.Length > 2) && ((clLine.Substring(0,
3) == "@ .") || (clLine.Substring(0, 3) == "@. ")))
{ // ECL comment character
locCommented++;
}
else
{
locExecutable++;
}
}
}
}
private void linesOfGuiCode(String clLine, ref String
commentStart, ref String commentEnd, ref String commentSingle)
{
determineLanguageCommentTags(ref commentStart, ref
commentEnd, ref commentSingle);
if ((commentStart == "") && (commentEnd == "") &&
(commentSingle == ""))
{ // We don't look for comments - if it's not blank,
it's executable
locExecutable++;
}
else
{
if (inComment)
{ // We're in a multi-line comment
locCommented++;
if (clLine.IndexOf(commentEnd) >= 0)
{ // This is the last line of the multi-line
comment
inComment = false;
}
}
else
{
if (clLine.IndexOf(commentStart) >= 0)
{
countNewMultiLineComment(clLine,
commentStart, commentEnd);
}
else
{
countSingleLineComments(clLine,
commentSingle);
}
}
}
}
private void countNewMultiLineComment(String clLine, String
commentStart, String commentEnd)
{
if (clLine.IndexOf(commentEnd) == -1)
{ // Start of a multi-line comment
inComment = true;
}
if ((clLine.IndexOf(commentStart) == 0))
{ // Nothing before the comment - the entire line is
commented
locCommented++;
}
else
{ // Something before the comment - count the line as
executable
locExecutable++;
}
}
private void countSingleLineComments(String clLine, String
commentSingle)
{
if ((commentSingle != "") &&
(clLine.IndexOf(commentSingle) >= 0))
{
if (clLine.IndexOf(commentSingle) == 0)
{ // The entire line is a comment
locCommented++;
}
else
{ // Only the end of the line is commented
locExecutable++;
}
}
else
{
locExecutable++;
}
}
private void determineLanguageCommentTags(ref String
commentStart, ref String commentEnd, ref String commentSingle)
{
// GUI
if ((elementSubType == "HTML") || (elementSubType ==
"CSS") || (elementSubType == "XML"))
{
commentStart = "<!--";
commentEnd = "-->";
}
else
{
if (elementSubType == "XSLT")
{
commentStart = "<xsl:comment>";
commentEnd = "</xsl:comment>";
}
else
{
if (elementSubType == "JS")
{
commentStart = "/*";
commentEnd = "*/";
commentSingle = "//";
}
}
}
}
private void lineOfCobolCode(String clLine)
{
// COBOL
if ((clLine.Length > 6) && (clLine.Substring(6, 1) ==
"*"))
{
locCommented++;
}
else
{
locExecutable++;
}
}
protected void updateProcXref(String upxLine)
{
// For this to work right, we need all items separated by
only one space
upxLine = normalizeSpace(upxLine);
switch (elementType)
{
case 'P':
establishTheCrossReferenceBasedOnCopySta
tement(upxLine);
break;
case 'L':
establishTheCrossReferenceBasedOnPerform
Statement(upxLine);
break;
}
}
private void
establishTheCrossReferenceBasedOnPerform
Statement(String upxLine)
{
// Establish the cross-reference based on perform
statement
if ((upxLine.Length > 9) && (upxLine.Substring(0, 8) ==
"PERFORM "))
{
String[] words = upxLine.Split(' ');
String[] pieces = words[1].Split('-');
// Don't count performs of the proc itself
if ((pieces[0] != elementId) &&
(isElement(pieces[0])))
{ // See if this is already in the xref
SqlCommand scCheck = new SqlCommand("SELECT
ProgName FROM Proc_Prog_Xref "
+ "WHERE ProgName = '" + elementId + "' "
+ "AND ProcName = '" + pieces[0] + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{
executeSQL("INSERT INTO Proc_Prog_Xref "
+ "(ProgName, ProcName, Passive,
EntryPoint) "
+ "VALUES ('" + elementId + "','"
+ pieces[0] + "',1,NULL)");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
private void
establishTheCrossReferenceBasedOnCopySta
tement(String upxLine)
{
// Establish the cross-reference based on copy statement
if ((upxLine.Length > 6) && (upxLine.Substring(0, 5) ==
"COPY "))
{
String[] words = upxLine.Split(' ');
String[] pieces = words[1].Split('-');
if (isElement(pieces[0]))
{ // See if this is already in the cross-reference
SqlCommand scCheck = new SqlCommand("SELECT
ProgName FROM Proc_Prog_Xref "
+ "WHERE ProgName = '" + elementId + "' "
+ "AND ProcName = '" + pieces[0] + "' "
+ "AND EntryPoint = '" + words[1] + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Add this program/proc to the table
executeSQL("INSERT INTO Proc_Prog_Xref "
+ "(ProgName, ProcName, Passive,
EntryPoint) "
+ "VALUES ('" + elementId + "','" +
pieces[0] + "',0,'" + words[1] + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
protected void updateRejectXref(String urxLine, String
urxProcessName)
{
Int32 rejectCode;
// Get rid of extra spaces
urxLine = normalizeSpace(urxLine);
if ((urxLine.IndexOf("REJCDE") >= 0) &&
(urxLine.IndexOf("MOVE ") >= 0))
{ // Line is "MOVE [something] TO REJCDE"
String[] words = urxLine.Split(' ');
if (Int32.TryParse(words[1], out rejectCode))
{
// Mask off narratives to get the lowest 4 digits
rejectCode = rejectCode % 10000;
if (rejectCode > 0)
{ // Is this reject already in the xref?
SqlCommand scCheck = new SqlCommand("SELECT
program FROM RejectsXref "
+ "WHERE program = '" + elementId + "' "
+ "AND reject_num = " +
rejectCode.ToString(), dbConn);
SqlDataReader drCheck =
scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Insert it
executeSQL("INSERT INTO RejectsXref "
+ "(program, reject_num,
last_updated, last_updated_by) "
+ "VALUES ('" + elementId + "'," +
rejectCode.ToString()
+ ",current_timestamp,'" +
urxProcessName + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
}
protected void updateCallXref(String ucxLine)
{
String[] words = normalizeSpace(ucxLine).Split(' ');
// Check for "PROGRAM-ID"
if (words[0] == "PROGRAM-ID")
{ // Save these off - we'll delete them at the end
programID.Add(words[1]);
}
if ((words.Length > 1) && (words[0] == "CALL"))
{
if ((words[1].Substring(0,1) == "\"") ||
(words[1].Substring(0,1) == "'"))
{ // Calling a literal - this is one we'll store
String callName =
words[1].Substring(1,words[1].Length - 2);
SqlCommand scCheck = new SqlCommand("SELECT
Element_ID FROM sdp_CSCI_CALL_Xref "
+ "WHERE Element_ID = '" + elementId + "' "
+ "AND Call_Name = '" + callName +
"'",dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // It's not there - insert it
executeSQL("INSERT INTO sdp_CSCI_CALL_Xref "
+ "(Element_ID, Call_Name) "
+ "VALUES ('" + elementId + "','" +
callName + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
protected void updateCull(String ucLine)
{
ucLine = normalizeSpace(ucLine);
if ( (ucLine.IndexOf("FETCH ") >= 0) ||
(ucLine.IndexOf("FIND ") >= 0)
|| (ucLine.IndexOf("MODIFY ") >= 0) ||
(ucLine.IndexOf("STORE ") >= 0)
|| (ucLine.IndexOf("DELETE ") >= 0) ||
(ucLine.IndexOf("INSERT ") >= 0)
|| (ucLine.IndexOf("REMOVE ") >= 0))
{
updateCullRecord(ucLine);
}
else
{
splitUpTheWordsAndCheckForDmsFieldNameOr
RprocDataName(ucLine);
}
}
private void
splitUpTheWordsAndCheckForDmsFieldNameOr
RprocDataName(String ucLine)
{
// Split up the words, and check for a DMS field name or
R-proc data name
String[] words = ucLine.Split(' ');
for (int i = 0; i < words.Length; i++)
{
if ((!isCobolKeyword(words[i])) && (!
hasSymbols(words[i])))
{
updateCullItem(words[i], ucLine);
}
}
}
// Update DML records in cull
protected void updateCullRecord(String ucrLine)
{
String[] words = ucrLine.Split(' ');
Int32 word = 0;
String column = "";
// --- CHECK #1 --- record name //
checkRecordName(words, ref word, ref column);
// --- CHECK #2 --- set name //
checkSetname(ucrLine, words, ref word, ref column);
}
private void checkSetname(String ucrLine, String[] words, ref
Int32 word, ref String column)
{
if ((ucrLine.IndexOf(" SET") >= 0) ||
(ucrLine.IndexOf("VIA ") >= 0))
{
String setName = "";
// Find the word "via" or "set"
word = 0;
while ((words[word] != "VIA") && (words[word] !=
"SET"))
{
word++;
}
if ((words[word] == "SET") && (word > 0))
{ // "FETCH xxx WITHIN xxxx SET", "REMOVE xxxx FROM
xxxxx SET", etc.
setName = words[--word];
}
else
{
if ((words[word] == "VIA") && (word <
(words.Length - 1)))
{ // "FETCH xxx VIA xxxx USING xxxx" format
statement
setName = words[++word];
}
}
if (setName != "")
{
// Is this a valid set name?
SqlCommand scSetChk = new SqlCommand("SELECT
set_name FROM dms_sets "
+ "WHERE set_name = '" + setName + "'",
dbHelp);
SqlDataReader drSetChk =
scSetChk.ExecuteReader();
if (drSetChk.HasRows)
{
// What column name do we update?
column = "";
if ((ucrLine.IndexOf("FETCH ") >= 0) ||
(ucrLine.IndexOf("FIND ") >= 0))
{
column = "Fetches";
}
else
{
if (ucrLine.IndexOf("INSERT") >= 0)
{
column = "Inserts";
}
else
{
if (ucrLine.IndexOf("REMOVE") >= 0)
{
column = "Removes";
}
}
}
if (column != "")
{ // Does it already exist in the cross-
reference?
SqlCommand scCheck = new
SqlCommand("SELECT Dbr FROM sdp_Dbr_Csci_Xref "
+ "WHERE Dbr = '" + setName + "'",
dbConn);
SqlDataReader drCheck =
scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Insert a new blank row
SqlCommand scInsert = new
SqlCommand("INSERT INTO sdp_Dbr_Csci_Xref "
+ "(Dbr, Csci, Fetches, Modifies,
Inserts, Stores, Removes, Deletes) "
+ "VALUES ('" + setName + "','" +
elementId + "',0,0,0,0,0,0)", dbConn);
scInsert.ExecuteNonQuery();
scInsert.Dispose();
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
SqlCommand scUpdate = new
SqlCommand("UPDATE sdp_Dbr_Csci_Xref "
+ "SET " + column + " = " + column +
" + 1 "
+ "WHERE Dbr = '" + setName + "' "
+ "AND Csci = '" + elementId +
"'", dbConn);
scUpdate.ExecuteNonQuery();
scUpdate.Dispose();
}
}
drSetChk.Close();
drSetChk.Dispose();
scSetChk.Dispose();
}
}
}
private void checkRecordName(String[] words, ref Int32 word,
ref String column)
{
// Find the word where we're doing the DML
while ((words[word] != "FETCH") && (words[word] !=
"FIND")
&& (words[word] != "MODIFY") && (words[word] !=
"STORE")
&& (words[word] != "DELETE") && (words[word] !=
"INSERT")
&& (words[word] != "REMOVE") && (word <
words.Length))
{
word++;
}
if ((word < (words.Length - 2))
&& ((words[word + 1] == "FIRST") || (words[word + 1]
== "NEXT")
|| (words[word + 1] == "PRIOR") || (words[word +
1] == "LAST")))
{ // "FETCH FIRST xxx", etc.
word++;
}
if ((word < (words.Length - 2)) && (words[word + 1] !=
"RECORD"))
{
// Determine the proper column name
if ((words[word] == "FETCH") || (words[word] ==
"FIND"))
{
column = "Fetches";
}
else
{
if (words[word] == "MODIFY")
{
column = "Modifies";
}
else
{
column = words[word].ToLower() + "s";
}
}
// The next word may be a record name
String recordName = words[++word];
// Is this name a valid record?
SqlCommand scRecChk = new SqlCommand("SELECT
record_name FROM dms_records "
+ "WHERE record_name = '" + recordName + "'",
dbHelp);
SqlDataReader drRecChk = scRecChk.ExecuteReader();
if (drRecChk.HasRows)
{ // Does the record already exist in the cross-
reference?
SqlCommand scCheck = new SqlCommand("SELECT CSCI
FROM sdp_Dbr_Csci_Xref "
+ "WHERE Dbr = '" + recordName + "' "
+ "AND Csci = '" + elementId + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Add a new zeroed-out row
SqlCommand scInsert = new SqlCommand("INSERT
INTO sdp_Dbr_Csci_Xref "
+ "(Dbr, Csci, Fetches, Modifies,
Inserts, Stores, Removes, Deletes) "
+ "VALUES ('" + recordName + "','" +
elementId + "',0,0,0,0,0,0)", dbConn);
scInsert.ExecuteNonQuery();
scInsert.Dispose();
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
// Update this count
SqlCommand scUpdate = new SqlCommand("UPDATE
sdp_Dbr_Csci_Xref "
+ "SET " + column + " = " + column + " + 1 "
+ "WHERE Dbr = '" + recordName + "' "
+ "AND Csci = '" + elementId + "'",
dbConn);
scUpdate.ExecuteNonQuery();
scUpdate.Dispose();
}
drRecChk.Close();
drRecChk.Dispose();
scRecChk.Dispose();
}
}
protected void updateCullItem(String uciWord, String uciLine)
{
bool used = false;
bool updated = false;
// Check to see if the word starts with "R" and has a
dash, and is not this proc
if ((uciWord.Substring(0,1) == "R")
&& (uciWord.Substring(3,1) == "-")
&& (uciWord.Substring(0,4) != elementId))
{
if (uciLine.IndexOf("PERFORM") >= 0)
{ // We've got a paragraph name performed
SqlCommand scTables = new SqlCommand("SELECT
DISTINCT table_name rt "
+ "FROM rdms_tables rt, rdms_table_columns
rtc "
+ "WHERE rt.table_name = rtc.table_name "
+ "AND rtc.r_proc_element_name LIKE '"
+ uciWord.Substring(0,4) + "%'",dbHelp);
SqlDataReader drTables =
scTables.ExecuteReader();
while(drTables.HasRows)
{ // See if this table already exists in the
cull look-up
int i = 0; // !WORK this is crap
}
}
else
{
if (uciLine.IndexOf("MOVE") >= 0)
{
if (uciLine.IndexOf("TO") >
uciLine.IndexOf(uciWord))
{
used = true;
}
else
{
updated = true;
}
}
else
{
updated = true;
}
}
}
else
{ // See if the word is a valid DMS field
}
}
// Establish connections with the database
protected void openSqlConnection(String oscServerName)
{
String connString = "";
if (oscServerName == "") {
oscServerName = "[servername]";
}
connString = "server=" + oscServerName +
";database=[database];User ID=[user];Password=[password];";
dbConn = new SqlConnection(connString);
dbConn.Open();
connString = connString.Replace("[database]","[another-
database]");
dbHelp = new SqlConnection(connString);
dbHelp.Open();
}
public String cscsRegValue(String crvKey)
{
SqlCommand crvCmd = new SqlCommand("SELECT reg_value "
+ "FROM sdp_registry "
+ "WHERE reg_key = '" + crvKey + "'", dbConn);
SqlDataReader crvDR = crvCmd.ExecuteReader();
if (crvDR.Read())
{
return(crvDR["reg_value"].ToString().Trim());
}
else
{
return("");
}
}
protected void executeSQL(String esText)
{
SqlConnection esConn = new
SqlConnection(dbConn.ConnectionString + "password=[password];");
SqlCommand esCmd = new SqlCommand(esText, esConn);
esConn.Open();
esCmd.ExecuteNonQuery();
esCmd.Dispose();
esConn.Close();
esConn.Dispose();
}
// Eliminates all embedded spaces more than one
protected String normalizeSpace(String nsText)
{
String workText = nsText;
while (workText.IndexOf(" ") >= 0)
{
workText = workText.Replace(" "," ");
}
return(workText);
}
// Returns "true" if the text passed is an element in CSCS
protected bool isElement(String ieText)
{
Boolean itExists = false;
SqlCommand ieCmd = new SqlCommand("SELECT Actv_Ind FROM
Active_Elements "
+ " WHERE Element_ID = '" + ieText + "'", dbConn);
SqlDataReader ieDR = ieCmd.ExecuteReader();
if (ieDR.HasRows) {
itExists = true;
}
ieDR.Close();
ieDR.Dispose();
ieCmd.Dispose();
return(itExists);
}
// Returns "true" if the word passed is a COBOL keyword
protected bool isCobolKeyword(String ickText)
{
Int32 i = 0;
while ((i < cobolKeywords.Length) && (ickText !=
cobolKeywords[i]))
{
i++;
}
if (i < cobolKeywords.Length)
{
return(true);
}
else
{
return(false);
}
}
// Returns "true" if the words passed has symbols in it
protected bool hasSymbols(String hsText)
{
if ( (hsText.IndexOf("(") >= 0) ||
(hsText.IndexOf(")") >= 0)
|| (hsText.IndexOf("\"") >= 0) ||
(hsText.IndexOf("'") >= 0)
|| (hsText.IndexOf("_") >= 0))
{
return(true);
}
else
{
return(false);
}
}
}
}
| |
|
| andrewmcdonagh wrote:
> Ok, so I downloaded and installed vs2005 express, loaded your class
> and started using the 'refactoring -> extract method' right click menu
> option....
>
> Here's what I've got so far....(if you paste it into your
> vs2005...you'll need to spend a few minutes sorting out the line wraps
> that posting it to here causes...)
Very . I'll be going from this (probably shortening some of those
method names), but I like it. :)
[snipped to save bits]
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
|
| andrewmcdonagh wrote:
> Cool!
>
> Yeah those names are a bit long (but then again, you only have to type
> them once as intellisense will create them for you every other time),
> but I did it deliberately to show the technique of 'convert comments
> into private method names' to get you started on 'self documenting'
> code.
That's . I tend to comment a lot - more than any other programmer
in our shop. (We proved that by looking at the output from this class -
my commenting average is between 22% and 28% compared to executable
lines in COBOL...)
> I'll continue to play with the class over the next few days when I get
> time and post the new versions on here.... (I'm thinking we'll
> transition to something like a dozen small classes working
> together....)
>
> This exercise is good for me too, as I've never used c# before, only
> read about it...
I appreciate it - I'm glad it's helping you too. Of course, I'm sort of
learning the two together, but I've been surprised how much Java works
in C# - and if it doesn't work, it probably just has a different name.
> Once we have this out of the way...the next biggest priority on your
> learning curve, should be how to develop code that has a full suite of
> automated Unit tests - NUnit is the unit testing framework of choice
> for .Net and should even be integrated into vs2005.... Normally I
> wouldn't do any code changes like these without a suite of unit tests
> to show me instantly if I break something... but one leasson at a
> time.
I'll have to look into that. How should I put this - code "robustness"
has been an issue with some of our .net pages.
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
|
| andrewmcdonagh wrote:
>
> 1) Create a new Interface called 'KeywordDictionary'
> with a single method 'isKeyword(String keyword)
>
> 2) Create a new Class called CobolKeywordDictionary
> 2.1) Copied the large keyword array into this new class.
> 2.2) Copied the 'isCobolKeyword(String ictText) method into this new
> class.
> 2.3) Changed the copied method's name to match the Interface's
> method (i.e 'isKeyword(String ictText)' )
> 2.4) Renamed the method parameter to be more self commenting:
> 'ictText' became 'keyword'
I like! I had been doing some working with namespaces and the like - I
took what you did, and some research prompted by Pete's comment about
the Dictionary class, and twisted it a bit. There is a List<T> class as
well, which doesn't require key/value combinations, and has a "Contains"
method. This is what it looks like now...
-8<--
using System;
using System.Collections.Generic;
using System.Text;
namespace CSCS.Util
{
class CobolKeywordDictionary : KeywordDictionary
{
// This is loaded with the keywords from the below table
private List<String> cobolKeywords = new List<String>();
// A list of COBOL keywords
private String[] keywords =
{ [oh yeah]
};
public CobolKeywordDictionary()
{
for (int i = 0; i < keywords.Length; i++)
{
cobolKeywords.Add(keywords[i]);
}
}
public bool isKeyword(String keyword)
{
return cobolKeywords.Contains(keyword.ToUpper());
}
}
}
->8--
I could still have the keywords in a separate XML file - but with the
reluctance of our customers to embrace new technology, that keyword list
won't be changing anytime soon.
This is really stuff! The intent of this look-up is to keep us
from hitting the database to determine if the name is a database name.
However, it just hit me when I was typing this e-mail - I could make
DataSets from the database tables, convert them to lists, and use the
list lookups for the cull building! No repetitive database access!
(You were just the witness to a huge light coming on in my head... And
no, it's not just the glare from where I don't have hair there
anymore... ;) )
I had tried to implement the above with a predicate, but it seemed like
cheating. Since I can't pass a parameter to the predicate method, I had
created a private String that I set to the keyword, then used the
StartsWith method on that string. My problem with that, though, is that
"ACC" came back as true, since "ACCEPT" starts with "ACC". I was going
to put a second check in there, using EndsWith, and then I said to
myself, this needs a "Contains" method or something. :) Looks like I
wasn't alone.
And - your inteface - I could come up with something like
NetworkRecordKeywordDictionary : KeywordDictionary
NetworkItemKeywordDictionary : KeywordDictionary
RelationalTableKeywordDictionary : KeywordDictionary
RelationalItemKeywordDictionary : KeywordDictionary
I actually *will* use a dictionary on the relational items, as I'll have
a proc data name (ex. R119-Home-ELC) that references an actual database
name (HOME_ELC in the HOME_USER table). I may have to add another
method to the interface for those, or change the return type - of
course, I guess at that point it's not really using the
KeywordDictionary interface. :)
Man - I'm excited. :) I really wish that there was a generic way to
code, though, that didn't have to know about what sort of database
backend you have. SqlDataAdapter is the DataAdapter for SQL Server,
while OdbcDataAdapter is the one for ODBC. If I could "genericise" (is
that a word?) those in the code, and just have it use whatever type of
connection I passed to it, I could actually run this against a copy of
the SQL Server database on my laptop (in MySQL or Access or something
else). (And yes, I know I could just code it with ODBC, but I don't
want it to run generically in production when there are libraries
specifically enhanced for it.)
> So, you might ask 'why the interface?' good question!
>
> There is no current need for it, but my OO and Unit testing sense
> tends to say create an interface more often than not - it will pay for
> itself sooner rather than later.
> Besides, Interfaces do not incur any runtime performance costs (that
> are worth caring about).
>
> What i mean about OO sense, is that now we have separated the
> Responsibility of specifying what a KeywordDictionary 'is', compared
> to its implementation - CobolKeywordDictionary in our case, or later,
> HtmlKeywordDictionary, JavaKeywordDictionary, etc....
>
> CobolKeywordDictionary, by using the class directly, I dont need to
> test it, by creating an instance of something that just happens to use
> it (CodeStatistics in our case).
That's great. :) I appreciate the list of steps you took in
refactoring the code, too - I haven't commented about the process much
because I so excited about the results, but I wanted you to know that I
did read it, and understand why you did what you did.
Thanks again for a great post, and lots of help! :) Before you know
it, I'll be able to put C# on my resume! (Not that they look at resumes
in the military...)
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
| Pete Dashwood 2007-02-04, 9:55 pm |
| Andrew,
I haven't had time to go through this in detail, but the approach is very
impressive.
You are demonstrating at a code level some of the most important concepts of
OO.
Great stuff!
Pete
<snipped to save space>
| |
| William M. Klein 2007-02-05, 6:55 pm |
| Just to "tie in" with my OO COBOL "collection classes" thread.
If anyone understands the OO COBOL specification AND this thread, am I correct
that *IF* one were doing this in COBOL that using the FACTORY Working-Storage
would "solve" the problem that Andrew mentions about,
" Thats ok, but the performance is going to suffer.
Every time you create an instance of this class, its going to: ..."
It is my understanding (limited as it is) that this is the point of (COBOL)
"factory" data (as opposed to method data).
--
Bill Klein
wmklein <at> ix.netcom.com
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170709103.296774.93650@q2g2000cwa.googlegroups.com...
> On Feb 5, 1:42 am, LX-i <lxi0...@netscape.net> wrote:
>
> snipped
>
>
>
> Thats ok, but the performance is going to suffer.
>
> Every time you create an instance of this class, its going to:
>
> 1) Create a Array of the string literals
> 2) Copy that array one by one into a List
>
> Then everytime you call 'isKeyword()' on your class, it asks the List
> if it contains the keyword. Which basically is going to loop through
> its internal data structure, one at a time until it find the keyword
> or finishes not finding it..
>
>
>
> Where as......
>
>
> using System;
> using System.Collections.Generic;
> using System.Text;
>
> namespace CodeStats
> {
> class FastCobolKeywordDictionary : KeywordDictionary
> {
> static Dictionary<String, String> keywords = new
> Dictionary<string,string>();
>
> // Static Constructor - means it will be called
> // once and only once, sometime between when the
> // program begins and the class is instantiated.
>
> static FastCobolKeywordDictionary()
> {
> //...
> keywords.Add("AUTHOR", null);
> keywords.Add("BEFORE", null);
> keywords.Add("BINARY-1", null);
> // ....
>
> }
>
> public bool isKeyword(String keyword)
> {
> return keywords.ContainsKey(keyword);
> }
>
> }
> }
>
> This class has a 'static constructor', which is called once and only
> once by the runtime system for you, at some point between the program
> starting and the first usage of the class.
>
> Plus, when 'isKeyword()' is called, it asks the Dictionary if it
> contains the keyword, which does a super fast lookup, which out
> looping through the entire collection.
>
> Dictionarys (And Hashtables) internally separate their contents into
> buckets based upon the hashcode of the Key. So when asked
> 'ContainsKey(...) they only need to look in the relevant (small)
> bucket for a match, instead of the entire collection.
>
>
>
>
>
>
>
> Sure and personally I wouldn't bother, it doesn't strike me like
> something that would change very often.
>
>
> oh ok...be care, this caching technique is widely know and so are its
> problems.
>
> e.g. when are updates applied to cache,
> concurrency issues
> etc...
>
>
> Yes best to just use '==' as this checks the string values rather than
> their references.
>
>
> note sure I follow you here...
>
> The interface is there to generalise the method, so if you change it
> to specialise again, then you code will need to
>
> if (cobol)
> return cobolKeywordDictionary.isKeyword(something);
> else
> return someOtherKeywordDictionary.isKeyword(Someting,
> andSomethingElse);
>
> always try to 'push' the knowledge of which one to call, to the other
> class (Our keyword dictionaries in this case), that way we can simply
>
> someDictionary.isKeyword(something);
>
>
>
> And that is a great technique - One I'd endorse.... which a twist...as
> above. push the knowledge of the Connection to the data source class
> itself, or pass it when you create an instance of the class.
>
> I tend to always abstract the data reading/writing behind a general
> purpose 'plain old c# ' interface, and let the implementors of that
> interface decide how/where to get their data from.
>
> e.g.
>
>
> interface LineCountReporter
> {
> void WriteTotalLineCount(String sourceFilename, int32
> lineCount);
> }
>
>
> class MySqlLineCountReporter : LineCountReporter
> {
>
> public MySqlLineCountReporter
> {
> dbConnection = // set the dbConnection here...
> }
>
> // provide the connection at object creation time only.
> public MySqlLineCountReporter(Connection connection)
> {
> dbConnection = connection
> }
> public void WriteTotalLineCount(String sourceFilename, int32
> lineCount)
> {
>
> // use MySql database code to write to a table.
> }
> }
>
>
>
>
| |
| Charles Hottel 2007-02-05, 6:55 pm |
|
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170671335.661227.165220@v33g2000cwv.googlegroups.com...
<snip>
I just want to say that I am enjoying this thread greatly!
Andrew your approach to helping Daniel is great also, expecially in a world
where so many have a first instinct to just be critical. Yor way seems more
like a caring teacher leading gently in the right direction.
Daniel you are doing very well. Do not worry that the first code you posted
was called "procedure oriented". You have to crawl befoe you can walk. Don
Higgins of z390 fame redid his assembler and macro processor from COBOL to
Java and it looked procedural to me at first, but it still provided a great
capability with far fewer lines of code than the COBOL version. Since then
he has added more features and in the process the code looks more and more
object oriented. With Adrews and others help you are geeting more and more
real experience with objects.
Thanks to all for an excellent thread!
| |
| Pete Dashwood 2007-02-05, 9:55 pm |
|
"William M. Klein" <wmklein@nospam.netcom.com> wrote in message
news:YXNxh.129392$5l2.119463@fe02.news.easynews.com...
> Just to "tie in" with my OO COBOL "collection classes" thread.
>
> If anyone understands the OO COBOL specification AND this thread, am I
> correct that *IF* one were doing this in COBOL that using the FACTORY
> Working-Storage would "solve" the problem that Andrew mentions about,
>
> " Thats ok, but the performance is going to suffer.
>
> Every time you create an instance of this class, its going to: ..."
Yes. That is correct. The factory can be used as Static (one time) storage.
You can also declare stuff in there as a PUBLIC PROPERTY (implicit GLOBAL
with GET SET methods generated by COBOL.) I have code that does this in OO
COBOL. The problem is that if you want to use these properties with DotNET
in C# (for example), you can't. The Interop services don't handle Factory
properties. (I don't know whether they handle Factory Methods, but I expect
they don't...) I'm looking for a better solution for this currently;
meantime, I have to pass what was a factory property to each of the Class
Methods. (Once the method has it, it can store and retrieve it in the
Factory definition and this works OK...)
>
> It is my understanding (limited as it is) that this is the point of
> (COBOL) "factory" data (as opposed to method data).
No. Factory seems to be very misunderstood in OO COBOL. What you mention is
ONE of the points for using Factory, there are others. (For instance (oops,
sorry, unconscious pun...:-)), you can use Factory Methods to do common
support functions that are required by a number of Methods, but which you
don't want instantiated every time a Method is instantiated. You can use
Factory to hold GLOBAL non-instance variables (like a count of the number of
objects currently generated, running control totals across all instances,
limited only by your imagination :-). It isn't just about static storage.
Pete.
| |
|
| andrewmcdonagh wrote:
> On Feb 5, 1:42 am, LX-i <lxi0...@netscape.net> wrote:
>
> snipped
Ouch! ;)
>
> Thats ok, but the performance is going to suffer.
>
> Every time you create an instance of this class, its going to:
>
> 1) Create a Array of the string literals
> 2) Copy that array one by one into a List
>
> Then everytime you call 'isKeyword()' on your class, it asks the List
> if it contains the keyword. Which basically is going to loop through
> its internal data structure, one at a time until it find the keyword
> or finishes not finding it..
>
>
>
> Where as......
>
>
> using System;
> using System.Collections.Generic;
> using System.Text;
>
> namespace CodeStats
> {
> class FastCobolKeywordDictionary : KeywordDictionary
> {
> static Dictionary<String, String> keywords = new
> Dictionary<string,string>();
>
> // Static Constructor - means it will be called
> // once and only once, sometime between when the
> // program begins and the class is instantiated.
>
> static FastCobolKeywordDictionary()
> {
> //...
> keywords.Add("AUTHOR", null);
> keywords.Add("BEFORE", null);
> keywords.Add("BINARY-1", null);
> // ....
>
> }
>
> public bool isKeyword(String keyword)
> {
> return keywords.ContainsKey(keyword);
> }
>
> }
> }
>
> This class has a 'static constructor', which is called once and only
> once by the runtime system for you, at some point between the program
> starting and the first usage of the class.
>
> Plus, when 'isKeyword()' is called, it asks the Dictionary if it
> contains the keyword, which does a super fast lookup, which out
> looping through the entire collection.
>
> Dictionarys (And Hashtables) internally separate their contents into
> buckets based upon the hashcode of the Key. So when asked
> 'ContainsKey(...) they only need to look in the relevant (small)
> bucket for a match, instead of the entire collection.
Ah... I shied away from that because I thought, "I don't need a
key-value pair - just the value." Would it still be acceptably
efficient to do the Add()s off the array defined in the constructor? I
could convert it to hard-coded Add()s, that would be easy enough.
Also, regarding the above - would there be anything wrong with making
isKeyword() a static method as well? Then, you wouldn't actually have
to create an object - you could just say something like
if (FastCobolKeywordDictionary.isKeyword(words[i])) {
// do something really 
}
I did that today with the NormalizeSpace method - I created a class
called CSCSFuncs (as plain Funcs was already taken), and made
NormalizeSpace() a class method.
(As a *way* aside, I found out that my web host, for $1 more a month,
offers ASP.NET with SQL Server 2005. I'm really tempted to cough up the
extra $12 to start working with some of my websites with this. Plus,
the plan still include PHP and MySQL, so my current stuff should
continue to work as-is. That way, I'd be able to get more experience in
the environment.)
>
> oh ok...be care, this caching technique is widely know and so are its
> problems.
These wouldn't updateable. Basically, I've got to look at every word in
a COBOL program to see if it's a database name. By excluding keywords,
I would not have to "hit the database" for those, which reduces my
database access time. Ditto for words with symbols. All I'm doing is
looking to see if that word is in the database of "database words". If
it is, I determine how it's being used (we track used vs. updated,
although it's kind of weak because an update of the group level item
updates all the elementary items; I think that the existing retrieval
walks up the hierarchy if you ask it to), then update the count.
I may have opportunity to use datasets for the update counts - but, I
would be AcceptChanges()ing often. Also, this process runs when a user
checks in a piece of source code - and, I can say with near certainty
that two people are going to be checking in the same item at the same
time! :) (If they are, we have other problems...)
(And yes, I know that this is "the original intent" of the code, which
may be changed over the years... Maybe straight ExecuteSQL()s would be
better (wrapped in another class, of course).)
>
> note sure I follow you here...
I'm not sure I followed myself... :)
> The interface is there to generalise the method, so if you change it
> to specialise again, then you code will need to
>
> if (cobol)
> return cobolKeywordDictionary.isKeyword(something);
> else
> return someOtherKeywordDictionary.isKeyword(Someting,
> andSomethingElse);
>
> always try to 'push' the knowledge of which one to call, to the other
> class (Our keyword dictionaries in this case), that way we can simply
>
> someDictionary.isKeyword(something);
Unless I return an array... Hmmm... [blink] Man, my power bill is
going to be sky-high this month! :)
But yes, I agree - the lookup for the relational items probably wouldn't
be an isKeyword() call, because I'm not implementing the interface if I
make an isKeyword() method that doesn't return a "bool" value, right?
>
> And that is a great technique - One I'd endorse.... which a twist...as
> above. push the knowledge of the Connection to the data source class
> itself, or pass it when you create an instance of the class.
>
> I tend to always abstract the data reading/writing behind a general
> purpose 'plain old c# ' interface, and let the implementors of that
> interface decide how/where to get their data from.
>
> e.g.
>
>
> interface LineCountReporter
> {
> void WriteTotalLineCount(String sourceFilename, int32
> lineCount);
> }
>
>
> class MySqlLineCountReporter : LineCountReporter
> {
>
> public MySqlLineCountReporter
> {
> dbConnection = // set the dbConnection here...
> }
>
> // provide the connection at object creation time only.
> public MySqlLineCountReporter(Connection connection)
> {
> dbConnection = connection
> }
> public void WriteTotalLineCount(String sourceFilename, int32
> lineCount)
> {
>
> // use MySql database code to write to a table.
> }
> }
I guess I'm not seeing this... How does this help me run the code on my
laptop against MySQL, e-mail to work, and run it on our server there
against SQL Server? (I don't mean this to sound as harsh as it probably
does, but I can't think of another way to word the question... Like I
said, I'm probably just not connecting the dots.)
Thanks again... :) I think I'm going to have to figure out how to use
Google Groups, because I don't want to lose this newsgroup in a couple
of w s when my cable modem is disconnected!
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
|
| andrewmcdonagh wrote:
[snip]
>
> interface DbUtils
> {
> public void recordLinesOfComments();
> ...
>
> }
>
> class MySqlDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
> class SqlDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
>
> class OracleDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
> Once you have these set of classes that implement the DB agnostic
> interface your application just then needs to decide which one to
> create an instance of to use. This could be done in the apps main
> class, using a commandline paramerter, machine name, environment
> variable, etc.
So, I've got basically the same thing 4 different times, depending on
the database I'm hitting. I don't guess there's any way around that,
but I do understand the flexibility it gets. The dots are connected
now. :) And, as I don't think I'm going to finish what I'm trying to
do here before I leave, this will help me set up the database on my machine.
(And, I should be able to make the other sets of code by replacing
"SqlConnection" with "OdbcConnection", "SqlDataAdapter" with
"OdbcDataAdapter", etc.)
> This technique is known as 'Inversion of Control'. Instead of the
> control over what implementation to use being hard coded, we invert
> that control by making it runtime configurable.
That's definitely what I was looking for. :) Thanks again for breaking
it down for me.
(Did you look at the "second C#" post - and if so, does it look like I'm
on the right track?)
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
| Pete Dashwood 2007-02-08, 6:55 pm |
|
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170954277.185118.185740@q2g2000cwa.googlegroups.com...
> On Feb 8, 1:27 am, LX-i <lxi0...@netscape.net> wrote:
>
> snipped...
>
>
> My pleasure...
>
> I've given it a quick scan but will need to have another look before
> commenting. Might be worth while you posting an update ...but if we
> can keep it in this thread, it will help keep the topic focused and
> together.
>
> The one main OO design point that you should eventually spot from
> where I'm taking you, is that numerous small classes with a single
> responsibility, when working together, can create a very simple but
> powerful design, with lots of code reuse.
>
> As a top of head metric, my designs tend to consist of 40% of classes
> containing a single method, which is no longer than a dozen lines of
> code. Another 55% would contain at most 6 methods, with the remaining
> 5% of classes having more than 6 methods.
>
> The 95% classes would having methods of no more than a dozen lines
> and all hold onto the **Single Responsibility Principle. The last 5%
> would be 'dodgy' and need refactoring...but then lifes too short and
> we do have to actually ship stuff!
>
> Regards
>
> Andrew
> ** Single Responsibility Principle - http://www.objectmentor.com/
> resources/articles/srp.pdf
>
I can't tell you what a relief it was to read these articles :-)
For some time now I have been trying to explain that an OO approach removes
the need for source code maintenance in the traditional sense. Classes and
methods should be encapsulated and "do what they do". When change is
required it should be new interfaces or extensions and NOT an internal
change to already working code. Apart from the obvious benefit of NOT
requiring regression testing, this approach also simplifies maintaining
applications. I came to learn this by working with COM component development
over a number of years.
Most people here, coming from a procedural background where the whole point
of good coding practice is to ensure that source code is easily maintained,
and one of the reasons for using COBOL in the first place is its
"self-documenting" nature, simply thought I was crazy.
Write applications then don't change the code? Impossible!
Of course, it isn't impossible and I've been doing it for some years now. I
see it as one of the most compelling arguments for using OO.
After a number of clumsy attempts to explain myself, I simply gave up...
It's like trying to explain the concept of "red" to a person who has been
blind since birth...
I have never studied the computer science covered in these articles, but
arrived at the same conclusions just by empirical practice.
This is the first tme I have seen some of the things I know innately,
expressed in a tangible and easily assimilable form. OK, there is a heap of
new jargon and acronyms, but the pure light of the underlying principles
shines through like a beacon.
I strongly recommend any COBOL programmer who is labouring under the burden
of heavy regression testing to at least browse the first article. (I
especially liked his description of "software rot" and what causes it :-))
Here is a direct link:
http://www.objectmentor.com/resourc...nd_Patterns.pdf
For me, the quote of the w is:
"The Open Closed Principle (OCP)
A module should be open for extension but closed for modification.
Of all the principles of object oriented design, this is the most important.
It originated
from the work of Bertrand Meyer. It means simply this: We should write our
modules
so that they can be extended, without requiring them to be modified. In
other
words, we want to be able to change what the modules do, without changing
the
source code of the modules."
Now, I wish I'd thought of that... :-)
Pete.
| |
| Charles Hottel 2007-02-08, 6:55 pm |
|
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170865585.775106.101930@j27g2000cwj.googlegroups.com...
> On Feb 5, 11:52 pm, "Charles Hottel" <chot...@earthlink.net> wrote:
>
> Thanks Charles,
>
> I find it very tiresome when people are overtly negative.
>
> On the java forums there's numerous 'forum police' whose sole postings
> consist of telling people off for
> 1) Top posting
> 2) not quoting
> 3) off topics
> 4) the colour of their shirts...
>
> My life is to short to worry about these things.
>
> Andrew
>
Yes I read the java newsgroups and I think it is just futile to try and
control what other people do. It takes much less energy to just ignore these
things and then you can invest that energy in things that are more
interesting.
| |
| Pete Dashwood 2007-02-08, 6:55 pm |
|
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170976759.429298.131560@v33g2000cwv.googlegroups.com...
<snipped>
>
>
>
> Glad you liked them... yes for me the OCP and SRP are two of the most
> important ones to start out with.
>
> Robert martin (the author) regularly hangs out in comp.object.
> (indeed he's having a hard time of it lately with an anti-oo crowd
> trying to poke wholes in OO through him).
>
> Do note though...that these principles whilst very easy to use and
> design in an OO language, can also work in some procedural languages,
> especially C.
Yes, the ideas can also be applied to COBOL design, that's why I encouraged
people here to read them. Nevertheless, the fact remains it is EASIER to
implement these ideas in a framework which is designed to support them.
Hence OO...
> For years now, Unix and Window's worlds have been using
> Libraries as part of applications (think DLLs). These libraries are
> loaded at runtime and are called via generic references (pointers to
> functions typically). This allowed us to create version 1.0 of our
> app, ship it and move on. Then later when a bug was found, we could
> just ship a new library instead of the whole app.
>
Yes. Exactly how COM components work. It is the detached and stable
interface wrapping that allows this to work, using the principles outlined
in the articles.
I have been extolling the virtues of component based development here for
some years now. The idea of building systems from "LEGO" blocks (read .dlls)
definitely works for me. Finding recently that I can still reuse these
components in a DotNET environment with C# has been a major factor in
deciding to move away from COBOL. Unmanaged code allows me to leverage my
investment in these components while I gradually move to a fully managed
scenario.
> Two other principles I keep in my bag of tricks are:
>
> 1) 'Favour delegation over inheritance'
> People tend to use inheritance for code reuse instead of modelling
> a relationship between two classes.
I can't remember the last time I explicitly used inheritance. In Java,
EXTENDS makes it easy and is useful, but in C# the inheritance tends to be
more implicit. I have only got onto delegation fairly recently and am still
understanding it. I knew Java events used a delegation model but never
really understood what it implied. Since learning C# I have a much better
grasp of it, but it is still early days for me. I can see your point and
will keep this in mind.
> Take a look at one of my latest posts to Daniel which shows how he
> could move the population of a Hashtable into its own class.
> Using delegation, its basically allows for a relationship between
> two classes to be Dynamic(made at runtime) instead of Inheritance,
> which is static(made at compile time)
I did see that and agree it is a better approach.
>
> 2) Favour polymorphism over type checking.
> I see a lot of people write code that asks an object for its type
> and then do something specific for that type. This approach whilst
> useful for a very small limited number of areas (Abstract Factories
> are the main), quickly leads to a brittle (low cohesive and tightly
> coupled) design.
>
Hmmm... hadn't thought about that. In C# you HAVE to be careful with typing
or the code won't compile. I don't think this precludes an abstract approach
though. I have some reservations about polymorphism (unless it is achieved
via separate interfaces). I don't like passing parameters to methods; I
prefer to get and set properties, then simply invoke the method without
parameters. This keeps a more simple external interface, but I'm grrdually
bending this as I understand more about polymorphism. It isn't a rule; more
of a guideline... :-)
Andrew, thanks again for the great posts you have been making and for
sharing your in depth experience here. I've certainly learned from them and
I'm sure others have too.
Cheers,
Pete.
| |
| William M. Klein 2007-02-08, 9:55 pm |
| WithOUT getting into the whole procedural vs OO debate, the recent posts in
this thread really DO remind me of "highly-modularized" procedural code that was
becoming semi-common in the late 80's and 90's (before COBOL lost its
"glitter"). In several IBM mainframe shops (which is what I knew best in those
days), the use of dynamic CALL statements with sub-programs with procedure
division that "could print on a single page of laser paper" gained a certain
(good and bad) reputation. OBVIOUSLY, the same goal of "encapsulating" logic
(and reuse of existing logic) was behind this.
It may or may not have anything to do with why OO hasn't caught on with IBM
mainframers, but the "highly-modularized" approach turned out to be a VERY bad
decision for some shops that were early implementors of IBM's LE (and, yes, I
still think it is similar to .NET CLR). In early IBM LE environments, the
overhead for doing "dynamic CALL" statements in COBOL was HORRENDOUS (especially
between old and new programs). Therefore, these "highly modularized"
applications came to screaming halts in actual mainframe production
environments. No change to code, just to run-times. (FYI, this has improved in
recent years. See LE "XPLINK" for example)
This may (or may not) have anything to do with why mainframers are "hesitant" to
move to many classes with small method applications.
(Just my $.02)
--
Bill Klein
wmklein <at> ix.netcom.com
"Pete Dashwood" <dashwood@removethis.enternet.co.nz> wrote in message
news:531o4vF1pgouiU1@mid.individual.net...
>
> "andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
> news:1170954277.185118.185740@q2g2000cwa.googlegroups.com...
>
> I can't tell you what a relief it was to read these articles :-)
>
> For some time now I have been trying to explain that an OO approach removes
> the need for source code maintenance in the traditional sense. Classes and
> methods should be encapsulated and "do what they do". When change is required
> it should be new interfaces or extensions and NOT an internal change to
> already working code. Apart from the obvious benefit of NOT requiring
> regression testing, this approach also simplifies maintaining applications. I
> came to learn this by working with COM component development over a number of
> years.
>
> Most people here, coming from a procedural background where the whole point of
> good coding practice is to ensure that source code is easily maintained, and
> one of the reasons for using COBOL in the first place is its
> "self-documenting" nature, simply thought I was crazy.
>
> Write applications then don't change the code? Impossible!
>
> Of course, it isn't impossible and I've been doing it for some years now. I
> see it as one of the most compelling arguments for using OO.
>
> After a number of clumsy attempts to explain myself, I simply gave up... It's
> like trying to explain the concept of "red" to a person who has been blind
> since birth...
>
> I have never studied the computer science covered in these articles, but
> arrived at the same conclusions just by empirical practice.
>
> This is the first tme I have seen some of the things I know innately,
> expressed in a tangible and easily assimilable form. OK, there is a heap of
> new jargon and acronyms, but the pure light of the underlying principles
> shines through like a beacon.
>
> I strongly recommend any COBOL programmer who is labouring under the burden of
> heavy regression testing to at least browse the first article. (I especially
> liked his description of "software rot" and what causes it :-)) Here is a
> direct link:
>
> http://www.objectmentor.com/resourc...nd_Patterns.pdf
>
> For me, the quote of the w is:
>
> "The Open Closed Principle (OCP)
>
> A module should be open for extension but closed for modification.
>
> Of all the principles of object oriented design, this is the most important.
> It originated
> from the work of Bertrand Meyer. It means simply this: We should write our
> modules
> so that they can be extended, without requiring them to be modified. In other
> words, we want to be able to change what the modules do, without changing the
> source code of the modules."
>
> Now, I wish I'd thought of that... :-)
>
> Pete.
>
| |
|
| andrewmcdonagh wrote:
>
> The one main OO design point that you should eventually spot from
> where I'm taking you, is that numerous small classes with a single
> responsibility, when working together, can create a very simple but
> powerful design, with lots of code reuse.
>
> As a top of head metric, my designs tend to consist of 40% of classes
> containing a single method, which is no longer than a dozen lines of
> code. Another 55% would contain at most 6 methods, with the remaining
> 5% of classes having more than 6 methods.
>
> The 95% classes would having methods of no more than a dozen lines
> and all hold onto the **Single Responsibility Principle. The last 5%
> would be 'dodgy' and need refactoring...but then lifes too short and
> we do have to actually ship stuff!
heh - true...
> ** Single Responsibility Principle - http://www.objectmentor.com/
> resources/articles/srp.pdf
Thanks for this site - that stuff is great! I see that I'm still not
thinking about things quite in an OO manner. However, the stuff on that
site is helping. :)
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
| |
| Pete Dashwood 2007-02-09, 7:55 am |
|
"William M. Klein" <wmklein@nospam.netcom.com> wrote in message
news:C3Syh.189491$jd2.135823@fe09.news.easynews.com...
> WithOUT getting into the whole procedural vs OO debate, the recent posts
> in this thread really DO remind me of "highly-modularized" procedural code
> that was becoming semi-common in the late 80's and 90's (before COBOL lost
> its "glitter"). In several IBM mainframe shops (which is what I knew best
> in those days), the use of dynamic CALL statements with sub-programs with
> procedure division that "could print on a single page of laser paper"
> gained a certain (good and bad) reputation. OBVIOUSLY, the same goal of
> "encapsulating" logic (and reuse of existing logic) was behind this.
>
> It may or may not have anything to do with why OO hasn't caught on with
> IBM mainframers, but the "highly-modularized" approach turned out to be a
> VERY bad decision for some shops that were early implementors of IBM's LE
> (and, yes, I still think it is similar to .NET CLR). In early IBM LE
> environments, the overhead for doing "dynamic CALL" statements in COBOL
> was HORRENDOUS (especially between old and new programs). Therefore,
> these "highly modularized" applications came to screaming halts in actual
> mainframe production environments. No change to code, just to run-times.
> (FYI, this has improved in recent years. See LE "XPLINK" for example)
>
> This may (or may not) have anything to do with why mainframers are
> "hesitant" to move to many classes with small method applications.
>
> (Just my $.02)
As you say, this is speculation. I didn't know that LE caused performance
problems with DYNAMIC calls and am astonished to hear it. It was common
practice on a number of European mainframe sites where I worked, to design
COBOL systems this way because of the flexibility and ease of maintenance; I
can't believe IBM were unaware of this and allowed LE to perform badly in
this area. (I DO believe it because you said it.)
As for such an experience causing hesitancy in moving to OO, I seriously
doubt it.
<broken record> MODULAR programming is NOT OO </broken record>... there are
some similarities, but there are differences also. The differences are
subtle, yet extremely important.
To decide that a bad experience with Modular programming presages a bad
experience with OO is like deciding that if the Christmas pudding is burned,
the tree will catch fire.
Pete.
| |
| Rick Smith 2007-02-09, 6:55 pm |
|
"Pete Dashwood" <dashwood@removethis.enternet.co.nz> wrote in message
news:533bj7F1r5ruaU1@mid.individual.net...
>
> "William M. Klein" <wmklein@nospam.netcom.com> wrote in message
> news:C3Syh.189491$jd2.135823@fe09.news.easynews.com...
posts[color=darkred]
code[color=darkred]
lost[color=darkred]
best[color=darkred]
with[color=darkred]
a[color=darkred]
LE[color=darkred]
actual[color=darkred]
run-times.[color=darkred]
>
> As you say, this is speculation. I didn't know that LE caused performance
> problems with DYNAMIC calls and am astonished to hear it. It was common
> practice on a number of European mainframe sites where I worked, to design
> COBOL systems this way because of the flexibility and ease of maintenance;
I
> can't believe IBM were unaware of this and allowed LE to perform badly in
> this area. (I DO believe it because you said it.)
>
> As for such an experience causing hesitancy in moving to OO, I seriously
> doubt it.
>
> <broken record> MODULAR programming is NOT OO </broken record>... there
are
> some similarities, but there are differences also. The differences are
> subtle, yet extremely important.
First, Mr Klein did not use the term "modular programming".
Second, "modular programming" may refer to something
specific (historically) or something generic (more recently).
Mr Klein's use ("highly-modularized") suggests generic.
Third, your use of "OO" is unclear. "OO" is used often
as an adjective, not as a noun and, as a noun, it is synonymous
with object-oriented design; thus, I am unable to determine
whether you intended the word "programming" as the noun
that "OO" modifies (MP is not OOP) or, if you intended
"design" (MP is not OOD).
Generically, modular programming includes all means for
decomposing computer programming problems into modules
(more easily manageable pieces of data and code); except,
procedural decomposition, which does not separate data.
Thus, structured design, functional decomposition, types
(user-defined and abstract data), object-oriented design, etc.,
are, generically, types of modular programming.
Not all modular programming is object-oriented design; but
all object-oriented design is modular programming ... at least
generically!
| |
| Pete Dashwood 2007-02-09, 6:55 pm |
|
"Rick Smith" <ricksmith@mfi.net> wrote in message
news:12spdp4n9or4i9a@corp.supernews.com...
>
> "Pete Dashwood" <dashwood@removethis.enternet.co.nz> wrote in message
> news:533bj7F1r5ruaU1@mid.individual.net...
> posts
> code
> lost
> best
> with
> a
> LE
> actual
> run-times.
> I
> are
>
> First, Mr Klein did not use the term "modular programming".
CLARIFICATION for those who live in a world of rigid definitions...(Great
idf you want to have pedantic debates, not so good if you just want to
discuss opinions.)
1. I was using Modular in the generic sense, as I believe that was what Bill
intended in his post..
2. OO was intended as "Object Orientation" and, as such, covers OOD and OOP
>
> Second, "modular programming" may refer to something
> specific (historically) or something generic (more recently).
> Mr Klein's use ("highly-modularized") suggests generic.
So you agree he intended generic. Why would you then not take my response as
generic?
>
> Third, your use of "OO" is unclear. "OO" is used often
> as an adjective, not as a noun and, as a noun, it is synonymous
> with object-oriented design; thus, I am unable to determine
> whether you intended the word "programming" as the noun
> that "OO" modifies (MP is not OOP) or, if you intended
> "design" (MP is not OOD).
Hopefully the above clarifies this.
>
> Generically, modular programming includes all means for
> decomposing computer programming problems into modules
> (more easily manageable pieces of data and code); except,
> procedural decomposition, which does not separate data.
Well that's your definition. I don't disagree, but it really doesn't matter
in the context of this particular discussion.
>
> Thus, structured design, functional decomposition, types
> (user-defined and abstract data), object-oriented design, etc.,
> are, generically, types of modular programming.
>
> Not all modular programming is object-oriented design; but
> all object-oriented design is modular programming ... at least
> generically!
The point I was making was that I'm heartily sick of hearing people say that
OO is a re-invention of modular programming. It isn't and, having used both
for considerable periods of my life, I recognise the differences.
That's really all I have to say on this.
Pete.
>
>
>
| |
| Charles Hottel 2007-02-09, 9:55 pm |
|
"William M. Klein" <wmklein@nospam.netcom.com> wrote in message
news:C3Syh.189491$jd2.135823@fe09.news.easynews.com...
> WithOUT getting into the whole procedural vs OO debate, the recent posts
> in this thread really DO remind me of "highly-modularized" procedural code
> that was becoming semi-common in the late 80's and 90's (before COBOL lost
> its "glitter"). In several IBM mainframe shops (which is what I knew best
> in those days), the use of dynamic CALL statements with sub-programs with
> procedure division that "could print on a single page of laser paper"
> gained a certain (good and bad) reputation. OBVIOUSLY, the same goal of
> "encapsulating" logic (and reuse of existing logic) was behind this.
>
> It may or may not have anything to do with why OO hasn't caught on with
> IBM mainframers, but the "highly-modularized" approach turned out to be a
> VERY bad decision for some shops that were early implementors of IBM's LE
> (and, yes, I still think it is similar to .NET CLR). In early IBM LE
> environments, the overhead for doing "dynamic CALL" statements in COBOL
> was HORRENDOUS (especially between old and new programs). Therefore,
> these "highly modularized" applications came to screaming halts in actual
> mainframe production environments. No change to code, just to run-times.
> (FYI, this has improved in recent years. See LE "XPLINK" for example)
>
> This may (or may not) have anything to do with why mainframers are
> "hesitant" to move to many classes with small method applications.
>
> (Just my $.02)
>
> --
> Bill Klein
> wmklein <at> ix.netcom.com
<snip>
I just do NOT buy the "highly-modularized approach is bad for performance
idea". Most performance problems are localized in a very small percentage of
the code. Without a performance monitoring tool most programmers guess wrong
about where the bottlenecks are. How many shops let application programmers
have access to tools like Strobe? In the absence of a monitoring tool, if
you can roll your own timing routines, then modular code can be an asset in
locating the slowest parts of code. In my experience if you do know where
the time is being spent the fact that the code is modularized does not
usually prevent a programmer from using the many techniques available to
optimize the code. YMMV.
| |
| Rick Smith 2007-02-09, 9:55 pm |
|
"Pete Dashwood" <dashwood@removethis.enternet.co.nz> wrote in message
news:534aglF1qc54mU1@mid.individual.net...
[snip]
> The point I was making was that I'm heartily sick of hearing people say
that
> OO is a re-invention of modular programming. It isn't and, having used
both
> for considerable periods of my life, I recognise the differences.
When you said as much recently, I found no reason
to object. I completely missed that point, this time,
and still don't see it. <g>
> That's really all I have to say on this.
Your choice! <g>
| |
| William M. Klein 2007-02-09, 9:55 pm |
| I agree that CALL performance is not the most common problem for (IBM mainframe)
performance, but ever since the days when VS COBOL II first came out, this HAS
been one place (especially dynamic CALL statement) where IBM has heard lots of
negative comments from customers. Recent (about OS/390 1.7 or so) and later
LE's have had much better performance than earlier versions. Today, I rarely
hear of this being a serious problem - but I know it is still something that IBM
looks at.
For those who haven't looked at the IBM performance guide, you might want to
check out the section on CALL performance. Some extracts include,
"When using CALLs, be sure to consider using nested programs when possible. The
performance of a CALL
to a nested program is faster than an external static CALL; external dynamic
calls are the slowest. CALL
identifier is slower than dynamic CALL literal."
and
"Performance considerations for using CALLs (measuring CALL overhead only):
CALL to nested programs was 50% to 60% faster than static CALL.
Static CALL literal was 45% to 55% faster than dynamic CALL literal.
Static CALL literal was 60% to 65% faster than dynamic CALL identifier.
Dynamic CALL literal was 15% to 25% faster than dynamic CALL identifier.
Note: These tests measured only the overhead of the CALL (i.e., the subprogram
did only a GOBACK);
thus, a full application that does more work in the subprograms may have
different results."
That last note ties in with Charles' comment as very few programs loop thru CALL
statements that don't do much. However, when you do have "highly modularized"
(in the sense of using COBOL CALL statement), this performance may gain
visibility.
--
Bill Klein
wmklein <at> ix.netcom.com
"Charles Hottel" <chottel@earthlink.net> wrote in message
news:HL8zh.229$Jl.113@newsread3.news.pas.earthlink.net...
>
> "William M. Klein" <wmklein@nospam.netcom.com> wrote in message
> news:C3Syh.189491$jd2.135823@fe09.news.easynews.com...
>
> <snip>
>
> I just do NOT buy the "highly-modularized approach is bad for performance
> idea". Most performance problems are localized in a very small percentage of
> the code. Without a performance monitoring tool most programmers guess wrong
> about where the bottlenecks are. How many shops let application programmers
> have access to tools like Strobe? In the absence of a monitoring tool, if you
> can roll your own timing routines, then modular code can be an asset in
> locating the slowest parts of code. In my experience if you do know where the
> time is being spent the fact that the code is modularized does not usually
> prevent a programmer from using the many techniques available to optimize the
> code. YMMV.
>
| |
| Pete Dashwood 2007-02-10, 3:55 am |
|
"William M. Klein" <wmklein@nospam.netcom.com> wrote in message
news:44bzh.214597$8R1.205013@fe04.news.easynews.com...
>I agree that CALL performance is not the most common problem for (IBM
>mainframe) performance, but ever since the days when VS COBOL II first came
>out, this HAS been one place (especially dynamic CALL statement) where IBM
>has heard lots of negative comments from customers. Recent (about OS/390
>1.7 or so) and later LE's have had much better performance than earlier
>versions. Today, I rarely hear of this being a serious problem - but I
>know it is still something that IBM looks at.
>
> For those who haven't looked at the IBM performance guide, you might want
> to check out the section on CALL performance. Some extracts include,
>
> "When using CALLs, be sure to consider using nested programs when
> possible. The performance of a CALL
> to a nested program is faster than an external static CALL; external
> dynamic calls are the slowest. CALL
> identifier is slower than dynamic CALL literal."
>
> and
>
> "Performance considerations for using CALLs (measuring CALL overhead
> only):
>
> CALL to nested programs was 50% to 60% faster than static CALL.
> Static CALL literal was 45% to 55% faster than dynamic CALL literal.
> Static CALL literal was 60% to 65% faster than dynamic CALL identifier.
> Dynamic CALL literal was 15% to 25% faster than dynamic CALL
> identifier.
>
> Note: These tests measured only the overhead of the CALL (i.e., the
> subprogram did only a GOBACK);
> thus, a full application that does more work in the subprograms may have
> different results."
>
> That last note ties in with Charles' comment as very few programs loop
> thru CALL statements that don't do much. However, when you do have
> "highly modularized" (in the sense of using COBOL CALL statement), this
> performance may gain visibility.
>
> --
> Bill Klein
> wmklein <at> ix.netcom.com
> "Charles Hottel" <chottel@earthlink.net> wrote in message
> news:HL8zh.229$Jl.113@newsread3.news.pas.earthlink.net...
>
The point being missed in all of the above is HOW LONG the worst case
scenario takes. If it is measured in milliseconds, then the percentages are
only meaningful where thousands of looping dynamic calls are made... not, in
my experience, a "usual" scenario.
If it is measured in seconds, then there is some cause for concern.
I can honestly say I have never worked on a site where dynamic call overhead
was even a consideration.
Very surprised to hear that LE degraded it.
Pete.
>
| |
| Howard Brazee 2007-02-12, 6:55 pm |
| On Sat, 10 Feb 2007 11:22:11 +1300, "Pete Dashwood"
<dashwood@removethis.enternet.co.nz> wrote:
>The point I was making was that I'm heartily sick of hearing people say that
>OO is a re-invention of modular programming. It isn't and, having used both
>for considerable periods of my life, I recognise the differences.
It isn't a re-invention of modular programming. But it is modular,
and it is programming.
And in a world where people use "database" to mean just about
anything, we need to specify when we want to exclude the more general
definitions if we expect good communications. --- even in a
programming news group, where "general" excludes non programmers.
This happens all over, not just in data processing.
| |
| Rick Smith 2007-02-12, 6:55 pm |
| X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.50.4522.1200
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4522.1200
X-Complaints-To: abuse@supernews.com
Lines: 48
Xref: number1.nntp.dca.giganews.com comp.lang.cobol:163094
"Howard Brazee" <howard@brazee.net> wrote in message
news:8nv0t297tmc6t3p6vk8tgun6lncm8g9060@
4ax.com...
> On Sat, 10 Feb 2007 11:22:11 +1300, "Pete Dashwood"
> <dashwood@removethis.enternet.co.nz> wrote:
>
that[color=darkred]
both[color=darkred]
>
> It isn't a re-invention of modular programming. But it is modular,
> and it is programming.
Modular programming is not programming. It is, generically,
any design method (for partitioning the programming task
into modules) implemented by means of programming.
Design is not programming!
The first use of "modular programming" dates from 1968
and appears to have included only those methods that
were lumped into "functional decomposition". About 1974,
modular programming included "structured design", which
used a different notation to present the design. By the
early-1980s, the definition expanded to include all methods
for "data-hiding".
Thus, OO is not a re-invention of modular programming.
It is modular programming!
OO extends modular programming in the same sense that
"radial tires" extends "tires", which previously included
"solid rubber tires", "bias-ply tires", etc.; or "jet aircraft"
extends "aircraft", which previously included
"propeller-driven aircraft", "gliders", "helicopters", etc.
The hesitancy that some appear to have for including
OO in modular programming may result from the belief
"OO is so much better than previous methods that it
does not deserve to be in the same class".
So make certain that your child's tricycle and your
wheelbarrow are equipped with radial tires--they are
so much better! <g>
| |
|
| andrewmcdonagh wrote:
> Daniel,
>
> Can you post the latest version of the code, as I think so long has
> passed its not worth me looking at what I think is your current code.
It'll be a bit. As I type packers are putting all my worldly goods into
boxes. :) The "my second C#" post is still the most recent - I've been
trying to wrap up everything at work and at home (which I'm starting to
think is an impossibility), so I haven't had too much time to revisit
that particular code.
(I have changed the DbUtil.cs file to be an interface, and created a
SqlDbUtil.cs file with the SQL Server implementation. I am also in the
process of changing the "string SQL together" methods to use parameters,
so as to make them not liable to SQL injection attacks.)
Also, I'm also going to try putting Vista on my laptop, as it has a
64-bit processor and supposedly Vista is good at actually utilizing it.
(It'll probably be like "What? You want more than *half* of me to do
something?!?!") Besides, I'm not happy with the way it's partitioned,
and if I repartition, I'd have to reload the OS anyway...
Once I do that, I'm going to create a fully-functioning version of CSCS
(the system this code supports) on my machine, and I'll be able to make
changes and see if they work. I'll keep you updated here...
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
|
|
|
|
|