COBOL / C# /Java Comparison COBOL C# Java Program Structure class-id HelloWorld as "Hello.Helloworld". method-id main static. local-storage section. 01 helloString string value "COBOL". procedure division using by value args as string occurs any. namespace Hello { public class HelloWorld { public static void Main(string[] args) { string helloString = "C#"; if length of args > 0 set helloString to args(1) end-if display "Hello, " & helloString & "!" end method. if (args.Length > 1) { helloString = args[0]; } System.Console.WriteLine("Hello, " + helloString + "!"); } } } end class. package Hello; public class HelloWorld { public static void main(String[] args) { String helloString = "Java"; if (args.length > 1) { helloString = args[0]; } System.out.println("Hello, " + helloString + "!"); } } Comments * in column 7 when comments out rest of line (COBOL fixed format) *> rest of the line comment, may follow COBOL statements *>> <summary>XML comments</summary> // Rest of line /* Multiple lines */ /// <summary>XML comments on single line</summary> /** <summary>XML comments on multiple lines</summary> */ // Rest of the line /* Multiple line */ /** Java doc. Type /** Eclipse will autocomplete */ Value Types condition-value binary-char unsigned, binary-char character binary-short (unsigned) binary-long (unsigned) binary-double (unsigned) float-short, float-long decimal DateTime (not a built-in COBOL type) Value Types bool byte, sbyte char short, ushort int, uint long, ulong float, double decimal DateTime (not a built-in C# type) Value Types boolean byte char short int long float, double Reference types object string Reference Types object string Reference Types java.lang.Object java.lang.String Initializing 01 isTrue condition-value value true. 01 hex binary-char unsigned value h"2a". *> Hex 01 octal binary-char unsigned value o"52". *> Octal 01 person object value null. 01 aName string value "Dwight". 01 grade character value "B". 01 today type DateTime value type DateTime::Parse("12/31/2007 12:15:00"). 01 amount decimal value 35.99. 01 gpa float-short value 2.9. 01 pi float-long value 3.14159265. 01 lTotal binary-double value 123456. 01 sTotal binary-short value 123. 01 usTotal binary-short unsigned value 123. 01 uiTotal binary-long value 123. 01 ulTotal binary-long unsigned value 123. Initializing bool isTrue byte hex Data Types Type Information 01 x binary-long. display x::GetType System.Int32 display type of binary-long System.Int32 display x::GetType::Name Type Conversion 01 d float-short value 3.5. conversion set i to d as binary-long (truncates decimal) *> Prints = true; = 0x2A; // hex object person = null; string aName = "Dwight"; char grade = 'B'; DateTime today = DateTime.Parse("12/31/2007 12:15:00"); decimal float double long short ushort uint ulong amount gpa pi lTotal sTotal usTotal uiTotal ulTotal = = = = = = = = 35.99m; 2.9f; 3.14159265; 123456L; 123; 123; 123; 123; Type Information int x; Console.WriteLine(x.GetType()); // Prints System.Int32 Console.WriteLine(typeof(int)); // Prints System.Int32 Console.WriteLine(x.GetType().Name); // prints Int32 Type Conversion float d = 3.5f; *> Prints Int32 int i = (int)d; // set to 3 (truncates decimal) *> Prints *> automatic *> set to 3 COBOL types not supported in C# or Java *> Only a few examples here 01 displayNumber pic 9(9).99. 01 computeNumber pic 9(9)V99. 01 alphaNumberic pic a(23). 01 binaryStorage pic x(12). *> Also groups and redefines - a few examples 01 arecord. 03 aSubRecord pic x(10). Date (not a built-in Java) Initializing boolean correct = true; byte b = 0x2A; // hex Object person = null; String name = "Dwight"; char grade = 'B'; Date today = Date.parse("12/31/2007 12:15:00"); float double long short int gpa pi lTotal sTotal iTotal = = = = = 2.9f; 3.14159265; 123456L; 123; 123; Type Information Use reflection Type Conversion float d = 3.5f; int i = (int)d; // set to 3 (truncates decimal) 03 aUnion aSubrecord. pic 9(10) redefines Constants 78 MAX_STUDENTS value 25. public, binary-long... *> optionally *> INITIALIZE ONLY - instance or static, may be initialized in constructor 01 MIN_DIAMETER float-short value 4.93 initialize only. const int MAX_STUDENTS = 25; final int MAX_STUDENTS = 25; // Can set to a const or var; may be initialised in a constructor readonly float MIN_DIAMETER = 4.93f; Enumeration enum-id Action. enum Action {Start, Stop, Rewind, 78 #Start. *> Start is a reserved word Forward}; 78 #Stop. enum Status {Flunk = 50, Pass = 70, 78 #Rewind. Excel = 90}; 78 #Forward. end enum. Action a = Action.Stop; enum-id Status. if (a != Action.Start) 78 Flunk value 50. Console.WriteLine(a + " is " + (int) 78 Pass value 70. a); // Prints "Stop is 1" 78 Excel value 90. end enum. Console.WriteLine((int) Status.Pass); program-id main. // Prints 70 display type Status::Pass as binary-long *> Console.WriteLine(Status.Pass); prints 70 // Prints Pass display type Status::Pass *> prints Pass end program. enum Action {Start, Stop, Rewind, Forward}; public enum Status { Flunk (50), Pass (70), Excel (90); private final int val; Status(int valIn) { this.val = valIn; } } Action a = Action.Stop; if (a != Action.Start) System.out.println(a); // Prints "Stop" System.out.println(Status.Pass.val); // Prints 70 System.out.println(Status.Pass); Operators Comparison = < > <= >= <> Comparison == < > <= Arithmetic + - * / function mod *>no direct COBOL equivalent to integer division ** Arithmetic + - * / % (mod) / (integer division if both operands are ints) Math.Pow(x, y) Arithmetic + - * / % (mod) / (integer division if both operands are ints) Assignment move, set, compute Assignment = += -= *= >>= ++ -- Assignment = += -= *= /= <<= >>= ++ -- Bitwise b-and, b-or, b-xor, b-not, b-left, b-right Logical and, or, not String Concatenation & Bitwise & | ^ Logical && || >= /= ~ & Comparison == < > <= != %= << | &= |= ^= <<= >> ^ ! Bitwise & | ^ >= Logical && || ~ != & %= << | &= |= ^= >> ^ ! //Note: && and || perform short-circuit logical evaluations String Concatenation + String Concatenation + Choices *>COBOL has no exact equivalent syntax to x ? greeting = age < 20 ? "What's up?" : y : z "Hello"; greeting = age < 20 ? "What's up?" : "Hello"; if age < 20 move "What's up?" to greeting else move "Hello" to greeting end-if // Good practice is that all consequents are enclosed in {} // although optional if 1 line if (age < 20) greeting = "What's up?"; else greeting = "Hello"; if x not = 100 and y < 5 multiply 5 by x multiply 2 by y end-if // Good practice is that all consequents are enclosed in {} // or are on the same line as if. if (age < 20) greeting = "What's up?"; else { greeting = "Hello"; } // Multiple statements must be enclosed in {} if (x != 100 && y < 5) { *> evaluate is preferred in COBOL rather than x *= 5; if/else if/else y *= 2; evaluate x } when > 5 multiply y by x when 5 if (x > 5) add y to x { when < 10 x *= y; subtract y from x } when other else if (x == 5) divide y into x { end-evaluate x += y; } else if (x < 10) evaluate color *> can be any type { when "turquoise" x -= y; when "red" } add 1 to r else when "turquoise" { add 1 to b x /= y; when "green" } // Multiple statements must be enclosed in {} if (x != 100 && y < 5) { x *= 5; y *= 2; } if (x > { x *= } else if { x += } else if { x -= } else { x /= } 5) y; (x == 5) y; (x < 10) y; y; // prints Pass add 1 to g when other add 1 to other-color end-evaluate // Every case must end with break or goto case switch (color) // Must be integer or string { case "turquoise": case "red": r++; break; case "turquoise": b++; break; case "green": g++; break; default: other++; break; // break necessary on default } switch (color) { case "turquoise": case "red": r++; break; case "turquoise": b++; break; case "green": g++; break; default: other++; break; } Loops Pre-test loops: perform until c >= 10 add 1 to c end-perform perform varying c from 2 by 2 until c > 10 display c end-perform Post-test loops: perform with test after until c >= 10 add 1 to c end-perform Array or collection looping 01 names string occurs any. 01 s string. set content of names to ("Rod", "Jane", "Freddy") perform varying s through names display s end-perform Breaking out of loops: 01 i binary-long value 0. perform until exit if i = 5 exit perform end-if add 1 to i end-perform Continue to next iteration: 01 i binary-long value 0 perform varying i from 0 by 1 until i >= 5 if i < 4 exit perform cycle end-if display i *> Only prints 4 end-perform Pre-test Loops: // no "until" keyword while (c < 10) { c++; } for (c = 2; c <= 10; c += 2) { Console.WriteLine(c); } Pre-test Loops: while (c < 10) { c++; } for (c = 2; c <= 10; c += 2) { System.out.println(c); } Post-test Loop: do { c++; } while (c < 10); Post-test Loop: do { c++; } while (c < 10); Array or collection looping string[] names = {"Rod", "Jane", "Freddy"}; foreach (string s in names) { Console.WriteLine(s); } Array or collection looping String[] names = {"Rod", "Jane", "Freddy"}; for (int i = 0; i < names.length; i++) { System.out.println(names[i]); } Breaking out of loops int i = 0; while (true) { if (i == 5) { break; } i++; } Breaking out of loops int i = 0; while (true) { if (i == 5) { break; } i++; } Continue to next iteration Continue to next iteration for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) if (i < 4) { { if (i < 4) continue; { } continue; Console.WriteLine(i); // Only prints } 4 System.out.println(i); // Only } prints 4 } Arrays 01 nums binary-long occurs 3 values 1, 2, 3. *> Can also do: set content of nums to (1, 2, 3) *> 01 *> 01 5 is the size of the array names string occurs 5. Can also do: names string occurs any. set size of names to 5 set names(1) to "Rod" *> first element indexed as 1 set names(6) to "Jane" *> throws IndexOutOfRangeException *> COBOL cannot resize an array - use copy 01 names2 string occurs 7. invoke type Array::Copy(names, names2, names::Length) *> or else: invoke names::CopyTo(names2, 0) *> or else: invoke type Array::Resize(names, 7) int[] nums = {1, 2, 3}; for (int i = 0; i < nums.Length; i++) { Console.WriteLine(nums[i]); } int[] nums = {1, 2, 3}; for (int i = 0; i < nums.length; i++) { System.out.println(nums[i]); } // 5 is the size of the array string[] names = new string[5]; names[0] = "Rod"; names[5] = "Jane"; // Throws System.IndexOutOfRangeException // 5 is the size of the array String[] names = new String[5]; names[0] = "Rod"; names[5] = "Jane"; // Throws java.lang.ArrayIndexOutOfBoundsExcept ion // C# can't dynamically resize an array. Just copy into new array. // Copy an array into a new array. string[] names2 = new string[7]; String[] names2 = new String[7]; // or names.CopyTo(names2, 0); Array.Copy(names, names2, names.Length); System.arraycopy(names, 0, names2, 0, names.length); float[,] twoD = new float[rows, cols]; twoD[2,0] = 4.5f; float[][] twoD; twoD = new float[rows][cols]; 01 twoD float-short occurs any, any. set size of twoD to rows, cols int[][] jagged = new int[3][] { new int[5], new int[2], new int[3] }; 01 jagged binary-long occurs any, occurs any. jagged[0][4] = 5; set size of jagged to 3 set size of jagged(1) to 5 set jagged(1, 5) to 5 // In Java this is just a multidimensional array int[][] jagged = {{1, 2, 3}, {1, 2, 3, 4, 5}, {1, 2}}; System.out.println("jagged[0][2] = " + jagged[0][2]); //prints 3 Functions method-id TestFunc. procedure division using value x as binarylong, reference y as binary-long, output z as binarylong. add 1 to x, y move 5 to z end method. // Pass by value (in, default), reference (in/out), // and reference (out) void TestFunc(int x, ref int y, out int z) { x++; y++; z = 5; } 01 a binary-long value 1. 01 b binary-long value 1. 01 c binary-long. *> c doesn't need initializing int a = 1, b = 1, c; // c doesn't need initializing TestFunc(a, ref b, out c); Console.WriteLine("{0} {1} {2}", a, b, c); // 1 2 5 invoke self::TestFunc(value a, reference b, output c) *> Or invoke self::TestFunc(a, b, c) display a space b space c // Accept variable number of arguments int Sum(params int[] nums) { int sum = 0; foreach (int i in nums) { sum += i; } return sum; } *> sum is an intrinsic function in COBOL 01 total binary-long. set total to function sum(4, 3, 2, 1) *> returns 10 *> To create a non intrinsic variable argument list function: method-id MySum. local-storage section. 01 i binary-long. procedure division using params nums as int total = Sum(4, 3, 2, 1); binary-long occurs any returns 10 returning mysum as binarylong. perform varying i through nums add i to mysum end-perform end method. // In Java there is no REF or OUT option on method parameters. // Everything is passed by value. However for a parameter of reference // type (i.e. not a primitive) it is the reference itself which is // passed by value, hence it appears to be pass-by-reference. void TestFunc(int x, int y, int z) { x++; y++; z = 5; } int a = 1, b = 1, c = 2; TestFunc(a, b, c); System.out.println(a + b + c); 1 2 // 1 // Accept variable number of arguments int Sum(int[] nums) { int sum = 0; for (int i = 0; i < nums.length; i++) { sum += i; } return sum; } // int[] nums = {1, 2, 3, 4}; int total = Sum(nums); // returns 10 *> then to call it: method-id main. local-storage section. 01 i binary-long. procedure division. set i to self::MySum(1, 2, 3, 4) display i end method. /* C# doesn't support optional arguments/parameters. Just create two different versions of the same function. */ void SayHello(string name, string // Java supports optional parameters prefix) void SayHello(String... strings) *> COBOL doesn't support optional { { arguments/parameters. Console.WriteLine("Greetings, " + for (String s : strings) *> Just create two different versions of the prefix + " " + name); System.out.println("Greetings, " same function. } + s); method-id SayHello. } procedure division using value nam as string, void SayHello(string name) prefix as { SayHello("Strangelove", "Dr"); string. SayHello(name, ""); SayHello("Madonna"); display "Greetings, " prefix space nam } end method. method-id SayHello. procedure division using value nam as string. invoke self::SayHello(nam "") end method. Strings Escape x"0a" x"09" "\" "" sequences *> line-feed *> tab *> backslash *> quote Escape sequences \r // carriage-return \n // line-feed \t // tab \\ // backslash \" // quote Escape sequences \r // carriage-return \n // line-feed \t // tab \\ // backslash \" // quote String concatenation 01 school string value "Harding" & x"09". set school to school & "University" *> school is "Harding (tab) University" String string school school String String school school Chars 01 letter character. 01 word character occurs any. set letter to school::Chars(0) letter is H set letter to type Convert::ToChar(65) letter is A set letter to 65 as character same thing set word to school::ToCharArray word holds Harding Chars char letter = school[0]; letter is H letter = Convert.ToChar(65); letter is A letter = (char)65; same thing char[] word = school.ToCharArray(); word holds Harding *> *> *> concatenation school = "Harding\t"; = school + "University"; // is "Harding (tab) University" concatenation school = "Harding\t"; = school + "University"; // is "Harding (tab) University" Chars // char letter = school.charAt(0); // letter is H // letter = (char)65; // letter is A // char[] word = school.toCharArray(); // // word holds Harding *> String literal 01 msg string value "File is c:\temp\x.dat". String literal string msg = @"File is c:\temp\x.dat"; // same as string msg = "File is c:\\temp\\x.dat"; String literal String msg = "File is c:\\temp\\x.dat"; String comparison 01 mascot string value "Beatles". if mascot = "Beatles" true if mascot::Equals("Beatles") true if mascot::ToUpper::Equals("BEATLES") true if mascot::CompareTo("Beatles") = 0 true *> *> *> *> Substring set s to mascot::Substring(1, 3) *> s is "eat" String comparison string mascot = "Beatles"; if (mascot == "Beatles") // true if (mascot.Equals("Beatles")) // true if (mascot.ToUpper().Equals("BEATLES")) // true if (mascot.CompareTo("Beatles") == 0) // true Substring s = mascot.Substring(1, 3)) "eat" String comparison String mascot = "Beatles"; if (mascot == "Beatles") // true if (mascot.contentEquals("Beatles")) // true if (mascot.toUpperCase().contentEquals(" BEATLES")) // true if (mascot.compareTo("Beatles") == 0) // true // s is Substring NB this is different behaviour to C#, startIndex endIndex Replacement String s = mascot.substring(1, 3); s = mascot.Replace("Beatl", "Monke")) // // s is "ea" s is "Monkees" Split Replacement Split 01 names string value s = mascot.replace("Beatl", "Monke"); "John,Paul,George,Ringo". string names = "John,Paul,George,Ringo"; // s is "Monkees" 01 parts string occurs any. // One name in each slot Split set parts to names::Split(",") string[] parts = names.Split(",".ToCharArray()); String names = Date to string "John,Paul,George,Ringo"; 01 dt type DateTime value new DateTime(1973, Date to string // One name in each slot 10, 12). DateTime dt = new DateTime(1973, 10, String[] parts = names.split("',"); 01 s string. 12); set s to dt::ToString("MMM dd, yyyy") *> string s = dt.ToString("MMM dd, yyyy"); Date to string Oct 12, 1973 // Oct 12, 1973 java.util.Date dt = new java.util.Date(); int to string java.text.SimpleDateFormat int to string 01 x binary-long value 2. dateformatMMDDYYYY = 01 y string. int x = 2; new set y to type x::ToString *> x is "2" string y = x.ToString(); // y is "2" java.text.SimpleDateFormat("MMddyyyy" ); string to int StringBuilder nowMMDDYYYY = string to int 01 x binary-long. new set x to type Convert::ToInt32("-5") *> x int x = Convert.ToInt32("-5"); // x StringBuilder(dateformatMMDDYYYY.form is -5 is -5 at(dt)); s = "Today is " + nowMMDDYYYY; Mutable string Mutable string int to string 01 buffer type System.Text.StringBuilder value new System.Text.StringBuilder buffer = int x = 2; System.Text.StringBuilder("two "). new System.Text.StringBuilder("two String y = Integer.toString(x); invoke buffer::Append("three") "); // y is "2" invoke buffer::Insert(0, "one ") buffer.Append("three "); String to int invoke buffer::Replace("two", "TWO") buffer.Insert(0, "one "); display buffer *> Prints "one TWO buffer.Replace("two", "TWO"); String minusFive = "-5"; three" Console.WriteLine(buffer); // Prints int z = new "one TWO three" Double(minusFive).intValue(); // x is -5 Replacement set s to mascot::Replace("Beatl", "Monke") *> s is "Monkees" Mutable string java.lang.StringBuilder buffer = new java.lang.StringBuilder("two "); buffer.append("three "); buffer.insert(0, "one "); buffer.replace(0, 2, "TWO"); //start, end, string - different to C# System.out.println(buffer); // Prints "one TWO three" Exception Handling *> Throw an exception // Throw an exception 01 excep type Exception value Exception up = new Exception("Something new Exception("Something is really is really wrong."); wrong."). throw up; raise excep // Catch an exception *> Catch an exception try try { set y to 0 y = 0; compute x = 10 / y x = 10 / y; catch excep *> Argument is optional, no } "When" keyword catch (Exception ex) // Argument is display excep::Message optional, no "When" keyword finally { invoke type Console.WriteLine(ex.Message); Microsoft.VisualBasic.Interaction::Beep } end-try finally { import java.lang.*; // Throw an exception Exception up = new Exception("Something is really wrong."); throw new EmptyStackException(); // Catch an exception try { int y = 0; int x = 10 / y; } catch (ArithmeticException ex) // Argument optional, no "When" keyword { System.out.println(ex.getMessage()); } Microsoft.VisualBasic.Interaction.Beep() finally ; { } System.out.println("\007"); } Namespaces *> At the file level $set ilnamespace "Harding.Compsci.Graphics" namespace Harding.Compsci.Graphics { ... *> The directive can also be set as a project } *> level to apply the name space to all classes in the project. // or namespace Harding { namespace Compsci // Packages are used to organize files or public types to avoid // type conflicts. // Package constructs can be mapped to a file system. package Harding.Compsci.Graphics ... // package cannot be nested { namespace Graphics { ... } } } using Harding.Compsci.Graphics; Classes / Interfaces Accessibility keywords public private internal protected protected internal static redefine Accessibility keywords public private internal protected protected internal static new Accessibility keywords public private Inheritance class-id FootballGame inherits type Competition. ... end class. Inheritance class FootballGame : Competition { ... } Inheritance class FootballGame extends Competition { ... } Interface definition interface-id IAlarmClock. ... end interface. Interface definition interface IAlarmClock { ... } Extending an interface interface-id IAlarmClock extends type IClock. Extending an interface ... interface IAlarmClock : IClock end interface. { ... } Interface implementation class-id WristWatch implements type Interface implementation IAlarmClock, type ITimer. ... class WristWatch : IAlarmClock, ITimer end class. { ... } protected static Interface definition interface IAlarmClock { ... } Extending an interface interface IAlarmClock extends IClock { ... } Interface implementation class WristWatch implements IAlarmClock, ITimer { ... } Constructors / Destructors class-id SuperHero. working-storage section. 01 _powerLevel binary-long. method-id new. procedure division. set _powerLevel to 0 end method. method-id new. procedure division using value powerLevel as binary-long. set _powerLevel to powerLevel end method. method-id Finalize override protected. *> Destructor code to free unmanaged resources. end method. end class. class SuperHero { private int _powerLevel; public class SuperHero { private int _powerLevel; public SuperHero() { _powerLevel = 0; } public SuperHero(int powerLevel) { this._powerLevel= powerLevel; } public void SuperHero() { _powerLevel = 0; } public void SuperHero(int powerLevel) { this._powerLevel= powerLevel; } ~SuperHero() { // Every class inherits the // Destructor code to free unmanaged finalize() method from resources. // java.lang.Object. The method is // Implicitly creates a Finalize called by the garbage method // collector when it determines no } more references to } // the object exist. It should be overridden to clean-up // non-Java resources eg closing a file. protected void finalize() { } } Using Objects 01 01 01 01 01 hero type SuperHero value new SuperHero. hero2 type SuperHero. obj object. reader type StreamReader. myLine string. set hero::Name to SpamMan set hero::PowerLevel to 3 invoke hero::Defend("Laura Jones") invoke type SuperHero::Rest *> Calling static method SuperHero hero = new SuperHero(); SuperHero hero = new SuperHero(); hero.Name = "SpamMan"; hero.PowerLevel = 3; hero.Name = "SpamMan"; hero.PowerLevel = 3; hero.Defend("Laura Jones"); SuperHero.Rest(); // Calling static method hero.Defend("Laura Jones"); SuperHero.Rest(); // Calling static method set hero2 to hero *> Both reference the same SuperHero hero2 = hero; // Both object reference the same object set hero2::Name to "WormWoman" hero2.Name = "WormWoman"; display hero::Name *> Prints WormWoman Console.WriteLine(hero.Name); // Prints WormWoman set hero to null *> Free the object hero = null ; // Free the object SuperHero hero2 = hero; // Both reference the same object hero2.Name = "WormWoman"; System.out.println(hero.Name); // Prints WormWoman hero = null ; // Free the object if hero = null set hero to new SuperHero end-if set obj to new SuperHero if obj is instance of type SuperHero display "Is a SuperHero object." end-if *> No 'using' construct in COBOL try set reader to type File::OpenText("test.txt") perform until exit set myLine to reader::ReadLine if myLine = null exit perform end-if end-perform finally if reader not = null invoke reader::Dispose end-if end-try if (hero == null) hero = new SuperHero(); if (hero == null) hero = new SuperHero(); Object obj = new SuperHero(); if (obj is SuperHero) { Console.WriteLine("Is a SuperHero object."); } Object obj = new SuperHero(); if (obj instanceof SuperHero) { System.out.println("Is a SuperHero object."); } // Mark object for quick disposal using (StreamReader reader = File.OpenText("test.txt")) { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); } } // Mark object for quick disposal FileInputStream fstream = new FileInputStream("test.txt"); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; while ((line = br.readLine()) != null) { System.out.println(line); } Structures (Value Types) *> COBOL uses valuetype-id to define a value type valuetype-id StudentRecord. 01 #name string public. 01 gpa float-short public. method-id new. procedure division using value nam as string, gpa as float-short. set #name to nam set self::gpa to gpa end method. end valuetype. class-id a. method-id main static. local-storage section. 01 stu type StudentRecord value new StudentRecord("Bob", 3.5). 01 stu2 type StudentRecord. procedure division. set stu2 to stu set stu2::name to "Sue" display stu::name *> Prints Bob display stu2::name *> Prints Sue end method. end class. // C# uses struct to define a value type //Java doesn't have struct. You may struct StudentRecord design a final class { // or a simple class to replace public string name; struct public float gpa; class StudentRecord { public StudentRecord(string name, public String name; float gpa) public float gpa; { this.name = name; public StudentRecord(String name, this.gpa = gpa; float gpa) } { } this.name = name; StudentRecord stu = new this.gpa = gpa; StudentRecord("Bob", 3.5f); } StudentRecord stu2 = stu; } StudentRecord stu = new stu2.name = "Sue"; StudentRecord("Bob", 3.5f); Console.WriteLine(stu.name); // StudentRecord stu2 = stu; Prints Bob Console.WriteLine(stu2.name); // stu2.name = "Sue"; Prints Sue System.out.println(stu.name); // Prints Bob System.out.println(stu2.name); // Prints Sue Properties class-id MyClass. working-storage section. 01 _size binary-long private. *> COBOL also allows you to expose fields as properties 01 _length binary-long property as "Length". 01 _width binary-long property as "Width" no get. 01 _breadth binary-long property as "Breadth" no set. private private private private int int int int _size; _length; _width; _breadth; public int Size { get { return _size; } set method-id get property #Size. { procedure division returning ret as binaryif (value < 0) long. { set ret to _size _size = 0; end method. } else method-id set property #Size. { procedure division using value val as _size = value; binary-long. } if val < 0 } set _size to 0 } else set _size to val public int Length end-if { end method. get end class. { return _length; class-id a. } method-id main. set local-storage section. { 01 foo type MyClass value new MyClass. _length = value; procedure division. } add 1 to foo::Size } display foo::Size end method. public int Width end class. { set { _width = value; } } private private private private int int int int _size = 0; _length = 0; _width = 0; _breadth = 0; public int getSize() { return _size; } public void setSize(int value) { if (value < 0) { _size = 0; } else { _size = value; } } public int getLength() { return _length; } public void setLength(int value) { _size = value; } public void setWidth(int value) { _width = value; } public int getBreadth() { return _breadth; } foo.Size++; public int Breadth { get { return _breadth; } } foo.Size++; Delegates / Events delegate-id MsgArrivedEventHandler. delegate void procedure division using value msg as string. MsgArrivedEventHandler(string message); end delegate. event MsgArrivedEventHandler class-id a. MsgArrivedEvent; working-storage section. 01 MsgArrivedEvent type MsgArrivedEventHandler event static. *> Delegates must be used with events method-id main static. procedure division. set MsgArrivedEvent to type Delegate::Combine(MsgArrivedEvent, new MsgArrivedEventHandler(self::myMsgArrivedEven tCallback)) as type MsgArrivedEventHandler invoke MsgArrivedEvent::Invoke("Test message") *> Throws exception if obj is null set MsgArrivedEvent to type Delegate::Remove(MsgArrivedEvent, new MsgArrivedEventHandler(self::myMsgArrivedEven tCallback)) as type MsgArrivedEventHandler invoke self::add_MsgArrivedEvent( new MsgArrivedEventHandler(self::My_MsgArrivedEve ntCallback)) invoke MsgArrivedEvent::Invoke("Test message 2") *> Throws exception if obj is null end method. method-id myMsgArrivedEventCallback static. procedure division using value str as string. display str end method. end class a. //There is no delegate concept in Java //The right-side C# program may be mimicked //with reflection technology. // Delegates must be used with events in C# MsgArrivedEvent += new MsgArrivedEventHandler(My_MsgArrivedEven tCallback); // Throws exception if obj is null MsgArrivedEvent("Test message"); MsgArrivedEvent -= new MsgArrivedEventHandler(My_MsgArrivedEven tCallback); using System.Windows.Forms; Button MyButton = new Button(); MyButton.Click += new System.EventHandler(MyButton_Click); private void MyButton_Click(object sender, System.EventArgs e) { MessageBox.Show(this, "Button was clicked", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); } Managed COBOL can also handle anonymous delegates (delegates to anonymous methods) via delegate constructors. Iterators class-id sillyCount. working-storage section. 01 c binary-long value 1 static. class SillyCount { static int c = 1; method-id main static. static void Main(string[] args) local-storage section. { 01 i binary-long. // Use foreach to loop through procedure division using value cmds as an iterator string occurs any. foreach(int i in doCount()) *> Use perform to loop over an iterator { perform varying i through self::doCount() System.Console.WriteLine(i); display i } end-perform } end method. // C# lacks specific syntax to mark *> Create an iterator by defining a member a method as an iterator as an iterator // you have to create a method with *> Using iterator-id instead of method-id the correct concrete form iterator-id doCount static. // of the IEnumerable interface and *> The return value if the iterator is then use the yield return defined using the // syntax inside the method. *> yielding verb static IEnumerable<int> doCount() procedure division yielding j as binary{ long. while (true) perform until false { add 1 to c c++; move c to j // C# uses an implicit *> Until the iterator is stopped, it return 'variable' rather than will yield on // the named one in COBOL. *> a goback verb Yield return returns goback // the value as the current value of the iterator *> then start again directly after the yield return c; goback *> on the next invocation of the // then starts immediately iterator after the multiply c by 10 giving j // yield return on the next if c < 50 invocation of goback // the iterator else if (c < 50) *> Stop iterator means the next { goback will yield return c * 50; In Java there is no YIELD feature, so the iterator implementation has to take care of state. Sample to follow... *> stop the iterator } stop iterator else goback { end-if // yield break marks the end-perform end of the iterator *> COBOL will implicitly stop iterator at yield break; the } *> end of the iterator definition. } *> In this example – the code never gets } here. } end iterator. end class. Generics - Consuming *> Consuming a generic method via type inference 01 result as type Tuple[binary-long binarylong]. *> Parameters are used to infer type set result to type Tuple::Create(1, 2) // Consuming a generic method via type inference // Consuming a generic method HashMap<Integer, Integer> result; System.Tuple<int, int> result; // Parameters are used to infer type result = new System.Tuple.Create(1, 2); result = new HashMap<Integer, Integer>(1, 2); *> Consuming a generic collection //Consuming a generic collection 01 x type List[string] value new List<string> x = new List<string>(); List[string]. int i; 01 i binary-long. for(i=0; i<101; ++i) 01 val string. { procedure division. x.Add(i.ToString()); perform varying i from 0 by 1 until i greater } than 100 foreach(string val in x) invoke x::Add(i::ToString) { end-perform Console.WriteLine(val); perform varying val through x } display val end-perform //Consuming a generic collection List<String> x = new ArrayList<String>(); for(Integer i = 0; i < 101; ++i) { x.add(i.toString()); } for(String val : x) { System.out.println(val); } Generics - Defining *> Generic class class-id Point3D using T. // Generic class class Point3D<T> *> With constraints class-id Point3D using T. constraints. constrain T implements type IComputable. // Generic class with constraints // Generic class with constraints class Point3D_c<T> where T : IComputable class Point3D_c <T extends IComputable> // Generic interface interface IComputable<T> //Generic interface interface IComputable<T> // Generic method public static Point3D<T> // Generic method MakePoint3D<T>(T x, T y, T z) public static <T> Point3D { MakePoint3D(T x, T y, T z) return new Point3D<T>(x, y, z); { } return new Point3D(x, y, z); } // Generic method with constraints public static void MakePoint3D<T>(T x, T // Generic method with constraints y, T z) where T : IComputable public static <T extends IComputable> { Point3D MakePoint3D(T x, T y, T z) return new Point3D<T>(x, y, z); { } return new Point3D<T>(x, y, z); // Generic value type } struct container<T, Y> { // No value type in Java, so generic public T a; simple class instead public Y b; class container<T, Y> } { public T a; // Generic value type with constraints public Y b; struct container<T, Y> where T : } IComputable // No value type in Java, so simple generic class with constraints // Generic iterator, use a parameterised class container<T extends class IComputable, Y> class a<T> { public static IEnumerable<T> itg(T // Generic iterator, use a x) parameterised class { class a<T> int val = 1; { while (val < 50) public static <T> T itg(T x) { { val++; int val = 1; yield return x; while (val < 50) } { } val++; } return x; } } // Using generic iterator } foreach (string dog in a<string>.itg("Dog")) System.Console.WriteLine(dog); for (String dog : a<string>) System.out.println(dog); *> Generic interface interface-id IComputable using T. *> Generic method method-id MakePoint3D static public using T. procedure division using value x as T y as T z as T returning ret as type Point3D[T]. *> With constraints method-id MakePoint3D static public using T. constraints. constrain T implements type IComputable. *> Generic value type valuetype-id container using T Y. 01 a T public. 01 b Y public. end valuetype. *> With constraints valuetype-id container using T Y. constraints. constrain T implements type IComputable. *> Generic iterator, use a parameterised class class-id a using T. iterator-id itg static. 01 val binary-long value 1. procedure division using value x as T yielding y as T. perform until val = 50 add 1 to val set y to x *> Just for example! goback end-perform end iterator. end class. *> To use, parameterise the class perform varying thg through type a[string]::itg("Dog") display thg end-perform // Generic class class Point3D <T> Synchronization / Locking *> Synchronize on an object's monitor, in this case *> the current object sync on self *> The code here is synchronised end-sync // Synchronize on an object's monitor, in this case // the current object lock (this) { // The code here is synchronised // Synchronize on an object's monitor, in this case // the current object synchronized (this) { // The code here is synchronised } } Attributes / Annotations C# terminology : attribute // Define attributes on a class [WebService(Description = "MyService")] [Obsolete] class MyClass { // Define attributes on a *> Define attributes on a field... field 01 a binary-long attribute [XmlAttribute("UpperB")] XmlAttribute("UpperB") [Obsolete] attribute Obsolete static. long a; *> Define attributes on a class class-id MyClass attribute WebService(name Description = "My service") attribute Obsolete. *> Define attributes on a property... *> Note that in this case, the attributes must follow *> the reserved word PROPERTY. 01 b binary-long property attribute XmlAttribute("UpperB") attribute Obsolete static. // Define attribute on a Define attributes on an event... Note that in this case, the attributes follow the reserved word EVENT. d type fred event attribute Obsolete static. // Annotation on a property @Deprecated private String prop; property private string prop; [Obsolete] public string b { [return:XmlAttribute("Upper *> *> must *> 01 // Java terminology : annotation // Annotation on a class @Author(name = "Benjamin Franklin", date = "3/27/2003") class MyClass { // Define attribute on a field @Deprecated long a; @Deprecated public String getb (){ return prop; } @Deprecated public void setb(String value) { prop = value; } B")] get { return prop; } [value:XmlAttribute("UpperB // Annotation on a method @SuppressWarnings("unchecked") public void main() { } ")] *> Define attributes on a method... method-id main attribute Obsolete static. procedure division. move 999 to a display a end method. *> Define attributes on a method parameter and return type method-id stat static. procedure division using l1 as binary-long attribute CLSCompliant(true) attribute MarshalAs(3) returning l2 as binarylong attribute CLSCompliant(true) attribute MarshalAs(2). move 999 to a display a set d to null end method. set { prop = value; } } // Define attribute on an event [Obsolete] public event fred d; // Define attribute on a method [Obsolete] public void main() { } // Define attributes on parameters and returns [return:CLSCompliant(true)] [return:MarshalAs(2)] public long Stat([CLSCompliant(true)][MarshalAs(3)]l ong l1) { return 12; } *> Define attributes on a property... method-id set property prop attribute property Obsolete static. procedure division using l1 as binary-long. move l1 to a end method. value; } end class. // Define attributes on a *> Define attribute on a delegate... delegate-id fred attribute Obsolete. procedure division using l1 as binary-long. end delegate. // Define attributes on a [Obsolete] public string b { set { prop = } delegate [Obsolete] public delegate void fred(long l1); } Beginning of sample programs Enumb.cbl enum-id Action. 78 #Start. *> Start is a reserved word 78 #Stop. 78 #Rewind. 78 #Forward. end enum. enum-id Stat as "Status". 78 Flunk value 50. 78 Pass value 70. 78 Excel value 90. // Define an annotation public @interface MyAnnotation { String doSomething(); int doCount(); } // Use an annotation @MyAnnotation (doSomething = "What to do", doCount = 1) public void myMethod() { } } end enum. program-id main. procedure division. display type Status::Pass as binary-long *> prints 70 display type Status::Pass *> prints Pass end program. Choices.cbl program-id a. working-storage section. 01 age binary-long. 01 greeting string. 01 x binary-long. 01 y binary-long. 01 color string value "turquoise". 01 r binary-long value 0. 01 b binary-long value 0. 01 g binary-long value 0. 01 other-color binary-long value 0. procedure division. if age < 20 set greeting to "What's up?" else set greeting to "Hello" end-if if x <> 100 and y < 5 multiply 5 by x multiply 2 by y end-if evaluate x when > 5 multiply when 5 add y to when < 10 subtract when other divide y end-evaluate y by x x y from x into x evaluate color *> can be any type when "turquoise" when "red" add 1 to r when "turquoise" add 1 to b when "green" add 1 to g when other add 1 to other-color end-evaluate end program. Loops.cbl program-id loops. working-storage section. 01 c binary-long value 0. 01 names string occurs any. 01 s string. 01 i binary-long value 0. procedure division. *>Pre-test loops: perform until c >= 10 *> No WHILE keyword add 1 to c end-perform perform varying c from 2 by 2 until c > 10 display c end-perform *> Post-test loops: perform with test after until c >= 10 add 1 to c end-perform *>Array or collection looping set content of names to ("Rod", "Jane", "Freddy") perform varying s through names display s end-perform *>Breaking out of loops: perform until false if i = 5 exit perform end-if display i add 1 to i end-perform *>Continue to next iteration: perform varying i from 0 by 1 until i >= 5 if i < 4 exit perform cycle end-if display i end-perform end program. Arrays.cbl program-id arrays. working-storage section. 01 nums binary-long occurs any. *> value 1, 2, 3. 01 names string occurs 5. *> 5 is the size of the array *> Can also do: *> 01 names string occurs any. 01 names2 string occurs 7. 01 twoD float-short occurs any, any. 01 jagged binary-long occurs any, occurs any. 01 rows binary-long value 3. 01 cols binary-long value 10. procedure division. set content of nums to (1 2 3 4) *> Resets the contents of the array (optionally changing the size) set size of names to 5 *> Create an array lf length 5 set names(1) to "Rod" *>set names(6) to "Jane" System.IndexOutOfRangeException *> first element indexed as 1 *> throws *> COBOL cannot directly resize an array - use copy invoke type Array::Copy(names, names2, names::Length) *> or else: invoke names::CopyTo(names2, 0) set size of twoD to rows, cols set size of jagged to 3 set size of jagged(1) to 5 set jagged(1, 5) to 5 end program. Functions-a.cbl class-id FunctionsA. method-id main static. local-storage section. 01 a binary-long value 1. 01 b binary-long value 1. 01 c binary-long. *> c doesn't need initializing 01 total binary-long. procedure division. invoke self::TestFunc(a, b, c) *> or invoke self::TestFunc(value a, reference b, output c) display a space b space c set total to function sum(4, 3, 2, 1) *> returns 10 invoke self::SayHello("Robert" "Mr.") invoke self::SayHello("Robert") end method. method-id TestFunc static. procedure division using value x as binary-long, reference y as binarylong, output z as binary-long. add 1 to x, y move 5 to z end method. *> COBOL doesn't support optional arguments/parameters. *> Just create two different versions of the same function. method-id SayHello static. procedure division using value name1 as string, prefix as string. display "Greetings, " prefix space name1 end method. method-id SayHello static. procedure division using value name1 as string. invoke self::SayHello(name1 "") end method. end class. Functions-b.cbl class-id FunctionsB. method-id main static. local-storage section. 01 i binary-long. procedure division. set i to self::mySum(1, 2, 3, 4) display i end method. method-id mySum static. local-storage section. 01 i binary-long. procedure division using params nums as binary-long occurs any returning mysum as binary-long. perform varying i through nums add i to mysum end-perform end method. end class. Strings.cbl program-id Strings. *> x"0d" *> carriage-return *> x"0a" *> line-feed *> x"09" *> tab *> "\" *> backslash *> "" *> quote working-storage section. *> Chars 01 letter character. 01 word character occurs any. 01 school string value "Harding" & x"09". *> String literal 01 msg string value "File is c:\temp\x.dat". 01 mascot string value "Beatles". 01 names string value "John,Paul,George,Ringo". 01 parts string occurs any. 01 dt type DateTime value new DateTime(1973, 10, 12). 01 s string. 01 x binary-long. 01 buffer type System.Text.StringBuilder value new System.Text.StringBuilder("two "). procedure division. *> string concatenation set school to school & "University" *> school is "Harding (tab) University" set letter to school(1:1) *> letter is H set letter to type Convert::ToChar(65) *> letter is A set letter to 65 as character *> same thing set word to school::ToCharArray *>word holds Harding *> string comparison if mascot = "Beatles" *> true display "Pass" end-if if mascot::Equals("Beatles") *> true display "Pass" end-if if mascot::ToUpper::Equals("BEATLES") *> true display "Pass" end-if if mascot::CompareTo("Beatles") = 0 display "Pass" end-if *> true *> Substring set s to mascot::Substring(1, 3) *> s is "eat" set s to mascot(2:3) *> Replacement set s to mascot::Replace("Beatl", "Monke") display s *> s is "Monkees" *> Split set parts to names::Split(",") *> Date to string set s to dt::ToString("MMM dd, yyyy") display s *> string to int set x to type Convert::ToInt32("-5") *> Oct 12, 1973 *> x is -5 *> Mutable string invoke buffer::Append("three") invoke buffer::Insert(0, "one ") invoke buffer::Replace("two", "TWO") display buffer *> Prints "one TWO three" end program. Exceptions.cbl program-id Exceptions. working-storage section. *> Throw an exception 01 exc type Exception value new Exception("Something is really wrong."). 01 x binary-long. 01 y binary-long. procedure division. *> Catch an exception try set y to 0 divide y into x catch exc *> Argument is optional, no "When" keyword display exc::Message finally invoke type Microsoft.VisualBasic.Interaction::Beep end-try raise exc end program. ClassesInterfaces.cbl *> Inheritance class-id FootballGame inherits type Competition. end class. *> Interface definition interface-id IAlarmClock. end interface. *> Extending an interface interface-id IAlarmClock inherits type IClock. end interface. *> Interface implementation class-id WristWatch implements type IAlarmClock, type ITimer. end class. interface-id IClock. end interface. interface-id ITimer. end interface. class-id Competition. end class. ConstructorsDestructors.cbl class-id SuperHero. working-storage section. 01 memberPowerLevel binary-long. method-id new. procedure division. set memberPowerLevel to 0 end method. method-id new. procedure division using value powerLevel as binary-long. set memberPowerLevel to powerLevel end method. method-id Finalize override protected. *> Destructor code to free unmanaged resources. *> Implicitly creates a Finalize method end method. end class. UsingObjects.cbl program-id UsingObjects. working-storage section. 01 hero type SuperHero value new SuperHero. 01 hero2 type SuperHero. 01 obj object. 01 reader type StreamReader. 01 myLine string. procedure division. *> No "With" construct set hero::Name to "SpamMan" set hero::PowerLevel to 3 invoke hero::Defend("Laura Jones") invoke type SuperHero::Rest *> Calling static method set hero2 to hero *> Both reference the same object set hero2::Name to "WormWoman" display hero::Name *> Prints WormWoman set hero to null *> Free the object if hero = null set hero to new SuperHero end-if set obj to new SuperHero if obj is instance of type SuperHero display "Is a SuperHero object." end-if *> No 'using' construct in COBOL try set reader to type File::OpenText("test.txt") perform until exit set myLine to reader::ReadLine if myLine = null exit perform end-if end-perform finally if reader not = null invoke reader::Dispose end-if end-try end program. class-id SuperHero. working-storage section. 01 #Name string property. 01 PowerLevel binary-long property. method-id Defend. procedure division using value attacker as string. end method. method-id Rest static. end method. end class. Structs.cbl valuetype-id StudentRecord. 01 #name string public. 01 gpa float-short public. method-id new. procedure division using value nam as string, gpa as float-short. set #name to nam set self::gpa to gpa end method. end valuetype. class-id Structs. method-id main static. local-storage section. 01 stu type StudentRecord value new StudentRecord("Bob", 3.5). 01 stu2 type StudentRecord. procedure division. set stu2 to stu set stu2::name to "Sue" display stu::name *> Prints Bob display stu2::name *> Prints Sue end method. end class. Properties.cbl class-id Properties. working-storage section. 01 _size binary-long private. method-id get property #Size. procedure division returning ret as binary-long. set ret to _size end method. method-id set property #Size. procedure division using value val as binary-long. if val < 0 set _size to 0 else set _size to val end-if end method. end class. class-id a. method-id main static. local-storage section. 01 foo type MyClass value new MyClass. procedure division. add 1 to foo::Size display foo::Size end method. end class. DelegatesEvents.cbl delegate-id MsgArrivedEventHandler. procedure division using value msg as string. end delegate. class-id DelegatesEvents. working-storage section. 01 MsgArrivedEvent type MsgArrivedEventHandler event static. *> Delegates must be used with events in C# method-id main static. procedure division. set MsgArrivedEvent to type Delegate::Combine(MsgArrivedEvent, new MsgArrivedEventHandler(self::My_MsgArrivedEventCallback)) as type MsgArrivedEventHandler invoke MsgArrivedEvent::Invoke("Test message") *> Throws exception if obj is null set MsgArrivedEvent to type Delegate::Remove(MsgArrivedEvent, new MsgArrivedEventHandler(self::My_MsgArrivedEventCallback)) as type MsgArrivedEventHandler invoke self::add_MsgArrivedEvent( new MsgArrivedEventHandler(self::My_MsgArrivedEventCallback)) invoke MsgArrivedEvent::Invoke("Test message 2") *> Throws exception if obj is null end method. method-id My_MsgArrivedEventCallback static. procedure division using value str as string. display str end method. end class. AnonymousDelegates.cbl class-id AnoDel. method-id main static. local-storage section. 01 d type del. 01 i type impl. 01 s string. procedure division. set s to "Hello from local variable" set i to new impl set d to new del(i::InstanceMethod) display d::Invoke("parameter to instance method") set d to new del(type impl::StaticMethod) display d::Invoke("parameter to static method") set d to new del(delegate returning r1 as string display s display "In anonymous method 1" set r1 to "Returned value from anon method 1" end-delegate) display d::Invoke("parameter to anonymous method 1") set d to new del(delegate using s1 as string returning r2 as string display s1 display "In anonymous method 2" set r2 to "Returned value from anon method 2" end-delegate) display d::Invoke("parameter to anonymous method 2") end method. end class. delegate-id. del. procedure division using value x as string returning y as string. end delegate del. class-id impl. method-id StaticMethod static. procedure division using value x as string returning y as string. display x display "In static method" set y to "Returned value from static method" end method. method-id InstanceMethod. procedure division using value x as string returning y as string. display x display "In instance method" set y to "Returned value from instance method" end method. end class. Iterators.cbl class-id Permute. *> Takes a command line of a string and finds all *> permutations of its characters. method-id main static. local-storage section. 01 start-str string. 01 s string. procedure division using value cmds as string occurs any. perform varying s through self::GetPermutations(cmds(1)) display s end-perform end method. iterator-id GetPermutations static. 01 i binary-long. 01 s string. procedure division using value str as string yielding res as string. if str::Length = 1 set res to str goback else perform varying i from 0 by i until i >= str::Length set s to string::Concat(str::Substring(0, i), str::Substring(i + 1)) perform varying res through self::GetPermutations(s) set res to string::Concat(str::Substring(i, 1), res) goback end-perform end-perform end-if stop iterator end iterator. end class. GenericsConsuming.cbl class-id GenericsConsuming. method-id main static. local-storage section, 01 x type List[type Tuple[binary-long, string]] value new List[type Tuple[binary-long, string]]. 01 i binary-long. 01 val type Tuple[binary-long, string]. procedure division. perform varying i from 0 by 1 until i greater than 100 invoke x::Add(type Tuple::Create(i, i::ToString)) end-perform perform varying val through x display val::ToString end-perform end method. end class. GenericsDefinitions.cbl class-id MessWithPoint3D. method-id main static. local-storage section. 01 vertex1 type Point3D[float-long]. 01 vertex2 type Point3D[float-long]. procedure division. set vertex1 to new Point3D[float-long](new ComputableFloat(1) new ComputableFloat(1) new ComputableFloat(1)) set vertex2 to new Point3D[float-long](new ComputableFloat(2) new ComputableFloat(2) new ComputableFloat(2)) display type Point3D[float-long]::GetDistance(vertex1 vertex2)::GetValue end method. end class. class-id Point3D using T. working-storage section. 01 _x type IComputable[T]. 01 _y type IComputable[T]. 01 _z type IComputable[T]. method-id get property x public. procedure division returning ret as type IComputable[T]. move _x to ret end method. method-id get property y public. procedure division returning ret as type IComputable[T]. move _y to ret end method. method-id get property z public. procedure division returning ret as type IComputable[T]. move _z to ret end method. method-id GetDistance public static. local-storage section. 01 inter type IComputable[T]. procedure division using value startPoint as type Point3D[T] endPoint as type Point3D[T] returning ret as type IComputable[T]. set set set set inter to startPoint::x::Subtract(endPoint::x)::Square inter to inter::Add(startPoint::y::Subtract(endPoint::y)::Square) inter to inter::Add(startPoint::z::Subtract(endPoint::z)::Square) ret to inter::Sqrt end method. *> The parameters of the new method link the type of IComputable to the *> type of the Point3D class and so fully enforce type safety method-id new public. procedure division using value x-in as type IComputable[T] y-in as type IComputable[T] z-in as type IComputable[T]. move x-in to _x move y-in to _y move z-in to _z end method. end class. interface-id IComputable using T. method-id #Add public. procedure division using value toAdd as type IComputable[T] returning ret as type IComputable[T]. end method. method-id #Subtract public. procedure division using value toSubtract as type IComputable[T] returning ret as type IComputable[T]. end method. method-id #Square public. procedure division returning ret as type IComputable[T]. end method. method-id #Sqrt public. procedure division returning ret as type IComputable[T]. end method. method-id GetValue public. procedure division returning ret as T. end method. end interface. class-id ComputableFloat implements type IComputable[float-long]. working-storage section. 01 my-value float-long. method-id new public. procedure division using value in-value as float-long. move in-value to my-value end method. method-id #Add public. local-storage section. 01 inter float-long. procedure division using value toAdd as type IComputable[float-long] returning ret as type IComputable[float-long]. compute inter = toAdd::GetValue + my-value set ret to new ComputableFloat(inter) end method. method-id #Subtract public. local-storage section. 01 inter float-long. procedure division using value toAdd as type IComputable[float-long] returning ret as type IComputable[float-long]. compute inter = my-value - toAdd::GetValue set ret to new ComputableFloat(inter) end method. method-id #Square public. local-storage section. 01 inter float-long. procedure division returning ret as type IComputable[float-long]. compute inter = my-value * my-value set ret to new ComputableFloat(inter) end method. method-id #Sqrt public. local-storage section. 01 inter float-long. procedure division returning ret as type IComputable[float-long]. set inter to function sqrt(my-value) set ret to new ComputableFloat(inter) end method. method-id GetValue public. procedure division returning ret as float-long. move my-value to ret end method. end class. Synchronization.cbl class-id Account. working-storage section. 01 balance binary-long. 01 r type Random value new Random. method-id new. procedure division using value init as binary-long. move init to balance end method. method-id Withdraw. procedure division using value amount as binary-long returning ret as binary-long. *> This condition will never be true unless the lock statement *> is commented out: if balance > 0 display "< 0" raise new Exception("Negative Balance") end-if sync on self if balance >= amount display "In critical section" *>display "Balance before Withdrawal : " balance *>display "Amount to Withdraw : -" amount compute balance = balance - amount *>display "Balance after Withdrawal : " balance move amount to ret else display "In critical section" move 0 to ret end-if end-sync end method. method-id DoTransactions. local-storage section. 01 i binary-long. procedure division. perform varying i from 0 by 1 until i = 100 invoke self::Withdraw(r::Next(1, 100)) end-perform end method. end class. class-id Test. method-id Main static. local-storage section. 01 threads type Thread occurs 10. 01 acc type Account value new Account(1000). 01 i binary-long. procedure division. perform varying i from 0 by 1 until i = 10 set threads(i + 1) to new Thread(new ThreadStart(acc::DoTransactions)) end-perform perform varying i from 0 by 1 until i = 10 invoke threads(i + 1)::Start end-perform end method. end class. Attributes.cbl class-id Attributes attribute WebService(name Description = "My service") attribute Obsolete. *> Define attributes on a field... local-storage section. 01 a binary-long attribute XmlAttribute("UpperB") attribute Obsolete static. *> Define attributes on a property... *> Note that in this case, the attributes must follow *> the reserved word PROPERTY. 01 b binary-long property attribute XmlAttribute("UpperB") attribute Obsolete static. *> Define attributes on an event... *> Note that in this case, the attributes must follow *> the reserved word EVENT. 01 d type fred event attribute Obsolete static. *> Define attributes on a method... method-id main attribute Obsolete static. procedure division. move 999 to a display a end method. *> Define attributes on a method parameter and return type method-id stat static. procedure division using l1 as binary-long attribute CLSCompliant(true) *> method parameters attribute MarshalAs(3) returning l2 as binary-long attribute CLSCompliant(true) *> return type attribute MarshalAs(2). move 999 to a display a set d to null end method. *> Define attributes on a property... method-id set property prop attribute Obsolete static. procedure division using l1 as binary-long. move l1 to a end method. end class. *> Define attribute on a delegate... delegate-id fred attribute Obsolete. procedure division using l1 as binary-long. end delegate fred. This article was written at the time of the Visual COBOL R4 release (GA June 2011). This sample code is supplied for demonstration purposes only on an "as is" basis and "is for use at your own risk".