Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / COBOL

Managed COBOL 101 - Named Generic Delegates

0.00/5 (No votes)
19 May 2010CC (ASA 2.5)2 min read 8.2K  
Managed COBOL 101 - Named Generic Delegates

Rolling Out the Big Guns - Micro Focus Managed COBOL Does Generic Delegates

Delegates are a managed code way of implementing methods by reference. In C, these things are called function pointers. However, function pointers are just plane dangerous (they cause things to crash and lack much in the way of type safety). So, generic delegates give the ability to reference methods as variables (local or working storage items), or in line, with all the type safety we expect from a modern language like Managed COBOL.

I have previously discussed anonymous delegates here. In this post, I want to make a COBOL example using a named generic delegate which is very similar to the VB and C# examples on MSDN. So here it is:

$set ilusing(System.Collections.Generic)

 class-id sorter.

     method-id main static.

         01 dinosaurs type List[String] value New List[String].

         invoke dinosaurs::Add("Pachycephalosaurus")
         invoke dinosaurs::Add("Amargasaurus")
         invoke dinosaurs::Add("")
         invoke dinosaurs::Add(Null)
         invoke dinosaurs::Add("Mamenchisaurus")
         invoke dinosaurs::Add("Deinonychus")
         display "Unsorted list:"
         invoke self::Display(dinosaurs)

         display "Sort with generic Comparison(Of String) delegate:"
         invoke dinosaurs::Sort(new Comparison[String](self::CompareDinosByLength))
         invoke self::Display(dinosaurs)
         display "--=== END ===--"
     end method.

     method-id CompareDinosByLength static.
         procedure division using by value
             x as string y as string returning ret as binary-long.
         evaluate true
             when x = null and y     = null move  0 to ret
             when x = null and y not = null move -1 to ret
             when y = null                  move  1 to ret
             when other
                 move x::Length::CompareTo(y::Length) to ret
                 if ret equals 0
                     move x::CompareTo(y) to ret
                 end-if
         end-evaluate
     end method.

     method-id Display private static.
         01 s string.
         procedure division using by value lis As type List[String].
         display ""
         perform varying s through lis
             if s equals null
                 display "(Nothing)"
             else
                 display '"' s '"'
             end-if
         end-perform
     end method.

 end class.

In the above code, we have defined a method called CompareDinosByLength. We do not call this method directly anywhere in the code. What we actually do is construct a delegate to it via the code new Comparison[String](self::CompareDinosByLength). Because we create the delegate to CompareDinosByLength with the generic argument [String], we are making a generic delegate. This is a very type safe approach to creating delegates because both the compiler and the runtime will make sure that the Comparison[String] delegate can only be a delegate to a method which takes string arguments. Generics are a very powerful way of enforcing signature type safety in Managed COBOL.

If we wanted to make a comparison to delegate for comparing Armadillo objects, this can also be done. The code would look like this: new Comparison[type Armadillo](self::CompareArmadillos). But if instead, we did this:new Comparison[type Armadillo](self::CompareDinosByLength), we would get a compile time error becauseCompareDinosByLength has String arguments, but we have defined the generic as being typed to have Armadillo arguments.

Here is what our Armadillo comparing method might look like:

* Compare Armadillos by tail length

     method-id CompareArmadillosstatic.
         procedure division using by value
             x as type Armadillo y as type Armadillo

             returning ret as binary-long.
         evaluate true

             when x.tailLength > y.tailLength move  1 to ret

             when x.tailLength < y.tailLength move -1 to ret

             when other move 0 to ret

         end-evaluate
     end method.

Footnote

Please note that in Managed COBOL, String is a type and a COBOL data form. So...

01 s1 String.
01 s2 type String.

... resolve to the same thing but...

$set ilusing(SomeNamespace)

01 a1 type Armadillo
01 a2 Armadillo

... will not even compile because the line defining a2 does not use the 'type' keyword.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License