Context:
Classes ValueTypes Interfaces Type Members
In this topic:
method-id methodA static. 01 s string value "Hello". procedure division. display s end method.
method-id methodB (paramA AS binary-short paramB AS binary-short) RETURNING paramC AS binary-short. set paramC = paramA * paramB end method.
See also the Core sample, which is available from $COBDIR/demo.
Methods can be either static methods or instance methods, and are by default instance. An instance method operates on a given instance of a class, whereas a static method does not operate on a given instance.
A static method can access static methods and static fields in its own class. It can also access instance methods and fields, in its own class or any other class, by constructing an object of the required class and accessing the method or field via that object.
For example, the following class contains static and instance methods, and static and instance fields.
class-id MyCounter. 01 totalCount binary-long static. 01 myCount binary-long. method-id New. procedure division. set myCount to totalCount set totalCount to totalCount + 1 end method. method-id GetCount. procedure division returning returnItem as binary-long. set returnItem to myCount end method. method-id GetTotalCount static. procedure division returning returnItem as binary-long. set returnItem to totalCount end method. method-id SetCount static. procedure division using by value aCount as binary-long. set totalCount to aCount end method. end class.
Here is the program that invokes the above code:
program-id StaticInstanceProgram. 01 myInstance1 type MyCounter. 01 myInstance2 type MyCounter. procedure division. invoke type MyCounter::SetCount(10) set myInstance1 to new type MyCounter set myInstance2 to new type MyCounter display myInstance1::GetCount() *> displays 10 display myInstance2::GetCount() *> displays 11 display type MyCounter::GetTotalCount() *> displays 12 end program.
To use static and instance methods:
The following modifiers indicate the extent to which the method inherits and is inherited:
specifies that this method overrides the inherited method of the same name and signature.
hides the superclass method only when the redefine method is invoked on an item defined as being of the subclass type.
An abstract method has no implementation. To use an abstract method, you inherit it and in the inheriting subclass, you provide the implementation of the method. An abstract class can contain methods that are not abstract, as well as abstract ones. The methods that aren't abstract can provide a default implementation, which can be overridden by a subclass method. For example:
class-id MyAbstractClass abstract. 01 myField value 0 binary-long property. method-id AbstractMethod abstract. *> no implementation end method. method-id NonAbstractMethod. *> not abstract procedure division. set myField to 1 *> Default behavior, which can be overridden end method. end class.
Non-abstract methods in an abstract class can provide a default implementation, which can be overridden by a subclass method.
class-id MySubClass inherits type MyAbstractClass. method-id AbstractMethod override. procedure division. *> Subclass method implements abstract method display "myField is: " myField *> displays 0 end method. method-id NonAbstractMethod override. procedure division. *> Subclass method overrides method that is not abstract set myField to 6 display "myField is: " myField *> displays 6 end method. end class.
To define and use methods in abstract classes:
An override method is a method that overrides an inherited virtual method of the same name and signature.
For example, a subclass Circle inherits from a superclass Shape. Both classes contain a Draw method. The Draw method in the Circle subclass overrides the Draw method in the Shape superclass.
class-id Shape. method-id Draw. display "let's draw a super shape" end method. end class. class-id Circle inherits type Shape. method-id Draw override. display "let's draw a circle" end method. end class.
To define an override method:
You cannot override a final method in the inherited class. You can override only virtual methods (methods not defined as final).
The REDEFINE keyword is used to hide a method inherited from a class. To hide an inherited method, declare it in the derived class using the same name and specify REDEFINE.
A redefine method is similar to an override method, in that it is a method with the same name and signature as a method in the superclass. However, unlike an override method, the redefine method might or might not be executed depending on how it is invoked. When the method is invoked on an item defined as being in the:
For example, we have two subclasses Circle and Square, which inherit from the Shapes superclass. All the classes have a Draw method. The Circle class's Draw method overrides the Draw method in the Shapes superclass. The Square class's Draw method redefines the Draw method in the Shapes superclass.
class-id Shape. method-id Draw. display "let's draw a super shape" end method. end class. class-id Circle inherits type Shape. method-id Draw override. display "let's draw a circle" end method. end class.
class-id Square inherits type Shape. method-id Draw redefine. display "let's draw a square" end method. end class.
You can invoke the Circle and Square classes as follows:
program-id. RedefineSampleProgram. 01 myShape type Shape. 01 myCircle type Circle. 01 mySquare type Square. procedure division. set myShape to new type Shape set myCircle to new type Circle set mySquare to new type Square invoke myCircle::Draw *> Circle Draw method is invoked invoke mySquare::Draw *> Square Draw method is invoked *> Shape Draw method is hidden, redefined set myShape to myCircle *> Superclass instance is set to subclass invoke myShape::Draw *> Circle Draw method is invoked *> as it overrides Shape Draw method set myShape to mySquare *> Superclass instance is set to subclass invoke myShape::Draw *> Shape Draw method is invoked as *> Square Draw method doesn't override it end program.
The above invocations produce the following output:
let’s draw a circle let’s draw a square let’s draw a circle let’s draw a super shape
Another place to use REDEFINE is where the method in the superclass is defined as FINAL and so it cannot be overridden. In this case, you can use REDEFINE to hide the superclass method.
A method that is declared as final is prevented from being overridden in any subclasses. This enables a class to inherit a superclass, while preventing a specific superclass method from being overridden in the subclass.
For example, we have a class MySubClass, which inherits from MySuperClass. MySuperClass has one final method and one virtual (not final) method. The subclass overrides the virtual method, but it cannot inherit or override the final method.
class-id MySuperClass. method-id VirtualMethod. *> Methods are virtual by default procedure division. display "Virtual method in the superclass" end method. method-id FinalMethod final. *> Final methods are not virtual procedure division. display "Final method in the superclass" end method. end class.
The subclass is defined as follows:
class-id MySubClass inherits type MySuperClass. method-id VirtualMethod override. procedure division. display "Overridden virtual method in the subclass" end method. * method-id FinalMethod override. *>COBCH0954 Method 'FinalMethod' cannot OVERRIDE a nonvirtual method end class.
The classes are invoked as follows:
program-id FinalOverrideSampleProgram. 01 mySuper type MySuperClass. 01 mySub type MySubClass. procedure division. set mySuper to new type MySuperClass invoke mySuper::FinalMethod() invoke mySuper::VirtualMethod() set mySub to new type MySubClass invoke mySub::VirtualMethod() end program.
The above sample program produces output as follows:
Final method in the superclass Virtual method in the superclass Overridden virtual method in the subclass
Although a final method cannot be overridden in a subclass, it can be redefined in the subclass.
The EXTENSION keyword declares a method as an extension method.
Extension methods enable you to add methods to existing types without the need to edit or recompile the code. Extension methods appear as additional methods available on an object instance while they are implemented elsewhere.
For example, the following extension method extends the string class, by adding a method to count the number of words in a string:class-id MyCount static. method-id CountWords extension. *> extension method is implicitly static procedure division using by value str as string returning wordCount as binary-long. set wordCount to str::Split(' ')::Length end method. end class.
To declare an extension method:
There is no special syntax for calling extension methods from managed COBOL. You consume an extension method in the same way as any other method, except you specify the first parameter as if it were the instance on which the method is called:
parameter-1::method-name(more parameters)
In JVM COBOL, there are two extensions that are preloaded before compilation:
These two extensions ensure that managed COBOL produces the same results, regardless of whether it is compiled to JVM COBOL or .NET COBOL. For more detail, see Extension Methods and Operators.
The SYNC modifier locks the values of the arguments sent to the method, so that they do not change while the method is processing.
When an argument is sent to a method and is received as a reference parameter, the value of the parameter and its corresponding sending argument might be updated. Without the SYNC modifier, the value of the sending argument is unknown, while the method is processing.
The SYNC modifier on a method is equivalent to wrapping the whole method in a SYNC statement.
For example:
01 a binary-long value 20. ... invoke Adjust(a) display a *> displays 93 method-id Adjust sync (reference x as binary-long). set x to x + 73 end method. end class.
In the above example, the SYNC modifier is applied to the method Adjust(). This ensures that the variables within the method (in this case, the variable x locally, but variable a in the invoking code) cannot be accessed until the method has finished processing.
If the FOR clause is specified, this method is an Explicit Interface Member Implementation. The method may not be invoked explicitly. It will be invoked implicitly when the corresponding method is invoked on an instance of this class which has been cast to the interface type.
Use of explicit interface implementation (via the FOR clause) is particularly useful when the class implements two different interfaces, and these two interfaces have a method with the same name and signature. In this case, by using the FOR phrase, you can supply two different implementations of the method for the two different interfaces.interface-id. "IAlarm1". method-id checkAlarm. procedure division using atime as binary-long. end method. end interface. interface-id. "IAlarm2". method-id checkAlarm. procedure division using atime as binary-long. end method. end interface. class-id BasicAlarm implements type IAlarm1 type IAlarm2. method-id checkAlarm for type IAlarm1. procedure division using atime as binary-long. ... end method. method-id checkAlarm for type IAlarm2. procedure division using atime as binary-long. ... end method. end class.
.NET COBOL utilizes the .NET async and await syntax to enable you to write responsive applications.
Asynchronous programming enables you to create tasks in your application that run independently from the main application thread. This means that when a task is busy, it executes in a different thread and your application remains responsive. After completion, the result of the task can be accessed by the caller.
Asynchronous programming is especially useful in applications that perform operations taking a long time to complete. These could be applications that handle web requests where you need the interface to stay responsive, or desktop applications that process big data or multiple resources.
You can create asynchronous applications by using the ASYNC and AWAIT syntax which indicate the method and the asynchronous operation it is waiting for. With it being simple enough for the programmer, the Compiler handles all the complicated work of running the asynchronous operation in a different thread, while the application continues to run in the main thread. The Compiler also ensures the correct operations are executed when the control is returned to the method at the await place.
In the following example, the ASYNC keyword indicates that your method is an asynchronous one. When execution reaches the AWAIT call, control is given to the .NET Task method that performs a delay of 1000ms. After the delay, control is given back to the method:
method-id ProcessItemsAsync async (#type as string, #count as binary-long) yielding items as string occurs any. invoke await type Task::Delay(1000) set items to table of ("a", "b", "c") end method.
Use the AWAIT keyword to begin an asynchronous operation and then continue executing the method after it completes. In the code below, the asynchronous operation is a delay performed by the Delay method of the Task threading class:
invoke await type Task::Delay(1000)
Task belongs to the System.Threading.Tasks namespace which includes types for writing asynchronous code. Task includes a number of methods that are useful for running code asynchronously.
The example below shows the result of ProcessItemsAsync being moved to items after completion:
declare items = await ProcessItemsAsync("user", 8)
Use async-void with an event handler that uses await statements. In the following example, the button is disabled with an artificial delay. The operation is asynchronous so the rest of your code will continue to execute after the delay of 1000ms without blocking the UI thread:
method-id button1_Click async-void (sender as object, e as type EventArgs). set button1::Enabled to false invoke await type Task::Delay(1000) set button1::Enabled to true end method.
The following example shows an async method which does not return a result:
method-id Task ProcessAsync() async. invoke await type Task::Yield() invoke type Console::WriteLine("async...") end method.
The following async method returns a result:
method-id ProcessItemsAsync async (#type as string, #count as binary-long) yielding items as string occurs any. invoke await type Task::Delay(1000) set items to table of ("a", "b", "c") end method.
Use the async-value keyword if your method should return a value task.
method-id AProcess async-value (x as condition-value) yielding result as string. if x invoke await type Task::Delay(1000) set result to "x" else set result to "y" end-if end method.