I am the trainer of one standard course “Programming Language Concept” within SAP and there is a set of concept Covariance and Contravariance, which has only built-in support by a subset of programming language like Java. For those ABAPers who don’t have chance to touch this concept in their daily work, I have built a small example to simulate how the concept works in ABAP as well for ease of understanding. The example explained in this example is just a prototype purely for training and education purpose.

Covariance and Contravariance in computer science

Both concept are closely related to inheritance in Object-Oriented world.
In this blog I use the following classes with hierarchical inheritance relationship.
For simplification reason no method is defined within these classes.

It is very straight-forward that both Dog and Cat are a kind of sub class of Animal, and ToyDog is a sub class of Dog.

However, how about the relationship between Animal container and Dog container? In order to describe the sub-typing relationship among more complex types ( in my example above, complex types mean Animal container and Dog container ) built via component type ( in my example component types refers to class Animal and Dog ).

You can find the definition of concept Covariance and Contravariance in Wikipedia.

Covariance

the complex type preserves the inheritance ordering of component type, which orders types from more specific to more generic. For example, we already have prerequisite that Dog is a sub class of Animal, and if Dog container is also a sub class of Animal container, we now say the subtyping relationship between Dog container and Animal container fulfills the Covariance contract.

Contravariance

Reverses this ordering.
In this blog, I will only focus on Covariance, since Contravariance works the same way as Covariance except that the inheritance relationship of complex types is reverted.

Covariance in Java

See this example below. In line 126, in signature of method forABAPer,
List<? extends Dog> declares a List container which must adhere to Covariance contract. ABAPers can analogize the symbol “?” to the generic type in ABAP such as ANY, ANY TABLE etc, which acts as a place holder and variable with concrete data type must be filled as parameter when the method is consumed.

List<? extends Dog> in method signature means the method can only accept a list container which fulfills Covariance contract, that is, the actual type of ? must be Dog itself, or any other sub class of Dog.

Due to Covariance contract, the Dog container created in line 113 and Toy Dog container in line 117 pass the syntax check, it is ok to call both via method forABAPer. For cat container in line 121, since Cat is not a sub class of Dog, syntax error is raised accordingly.

Contravariance contract, on the other hand, is defined via
“<? super T>“, where T is a generic COMPONENT type of super class, and ? is the concrete type you must specify when you call the method.

Covariance and Contravariance is widely used in JDK implementation and many Java framework like Spring.

See one example below about the implementation of utility method java.util.Collections.copy, which does a shadow copy of each element from source container to destination container.

Another guideline of Covariance and Contractvariance is the so called PECS https://en.wikipedia.org/wiki/Wildcard_(Java) which is much more sophisticated and is out of scope of this blog.

How to simulate Covariance in ABAP

In ABAP since we don’t have real container type with Object-Oriented behavior, we have to simulate Covariance with internal table plus interface instead.

(1) declare a tag interface

I declare a tag interface ZIF_COVARIANCE without any method defined there, but only with two attribute G_TYPE and C_TYPE.
Here G_TYPE simulates generic type of list container and C_TYPE simulates concrete type “?” in Java, which must be filled by a real data type when method is called.

(2) build a Animal container with Covariance contract

In this container class, I assign the tag interface ZIF_COVARIANCE to it, meaning that this container is now under the Covariance syntax check.

The generic type G_TYPE is now determined in the design time, ZCL_DOG.
This means in compiler time, only Covariance compliant code can pass syntax check:

When you instantiate a new instance of this animal container, the concrete class type you use must be either ZCL_DOG itself, or any sub class of ZCL_DOG.

When you try to add a new animal to this animal container, the data type of the element to be inserted must be either ZCL_DOG itself, or any sub class of ZCL_DOG.

(3) implement a custom Covariance syntax check

In this animal container class, I use an internal table with type ZCL_ANIMAL to store the inserted animal reference.
types TY_REF type ref to ZCL_ANIMAL .
data: DATA type STANDARD TABLE OF ty_ref .
As a result, by default the following code will pass the syntax check, since ZCL_CAT is also a sub class of ZCL_ANIMAL, so the instance of it could be successfully inserted to internal table with TYPE REF TO ZCL_ANIMAL, although this is a violation of Covariance.
There are two places in the following code which do not obey Covariance:

In line 4, since the animal container has already marked generic type as ZCL_DOG, the concrete data type must be either ZCL_DOG itself, or any sub class of ZCL_DOG. ZCL_CAT is not allowed.

In line 11, it is not allowed to insert a cat to a dog container.

The expected behavior is: once you click Ctrl+F2 to trigger syntax check, all Covariance violation are found and listed, see example below:

How to implement Covariance Syntax check in class builder

The main logic of Covariance check is done in method ZCL_ABAP_COVARIANCE_TOOL~COVARIANCE_SYNTAX_CHECK, which only consists of 45 lines:

METHOD covariance_syntax_check.DATA: lv_include TYPE progname,lv_main    TYPE progname,lv_index   TYPE int4 VALUE 1.FIELD-SYMBOLS:<method> LIKE LINE OF mt_result.initialize( ).ms_working_method = is_method_def.fill_method_source( ).lv_include = cl_oo_classname_service=>get_method_include( is_method_def ).lv_main = cl_oo_classname_service=>get_classpool_name( is_method_def-clsname ).DATA(lo_compiler) = NEW cl_abap_compiler( p_name = lv_main p_include = lv_include ).lo_compiler->get_all( IMPORTING p_result = mt_result ).LOOP AT mt_result ASSIGNING <method>.CASE <method>-tag.WHEN 'ME'.DATA(ls_method_detail) = get_method_type( <method>-full_name ).fill_caller_variable_name( EXPORTING iv_current_index = lv_indexCHANGING  cs_method_detail = ls_method_detail ).IF ls_method_detail-method_signature IS NOT INITIAL.fill_call_parameter( EXPORTING iv_current_index = lv_indexCHANGING cs_method_detail = ls_method_detail ).ENDIF.ls_method_detail-line = <method>-line.APPEND ls_method_detail TO mt_method_detail.WHEN OTHERS.ENDCASE.ADD 1 TO lv_index.ENDLOOP.DELETE mt_method_detail WHERE caller_variable_name IS INITIAL.LOOP AT mt_method_detail ASSIGNING FIELD-SYMBOL(<result>).CHECK is_covariance_check_needed( <result>-caller_variable_name ) = abap_true.CASE <result>-method_type.WHEN cs_method_type-constructor.check_ctor_covariance( <result> ).WHEN cs_method_type-instance.check_instance_covariance( <result> ).ENDCASE.ENDLOOP.RT_ERROR_MESSAGE = MT_ERROR_MESSAGE.ENDMETHOD.

(1) perform syntax analysis on instance method and constructor method

With help of CL_ABAP_COMPILER, I can get a list of all methods call and used variable within the method being checked. The used information returned by CL_ABAP_COMPILER has the following format.
As the Covariance check only makes sense on method call,

so in my Covariance syntax analysis, I will only handle the entry for method call ( marked with tag “ME” in CL_ABAP_COMPILER returning result ).

After the loop in line 17 is finished, I have successfully regularized the result from CL_ABAP_COMPILER with raw format to my customized data format as below:

The internal table mt_method_detail has line type defined by myself, TY_METHOD_DETAIL.

Take the first row in above screenshot for example

Method_type 1 means it is a constructor call.
CALLER_VARIABLE_NAME lo_dog_container means this variable is instantiated via keyword NEW.

METHOD_CLS_NAME ZCL_ANIMAL_CONTAINER means the variable lo_dog_container is initialized by NEW with type ZCL_ANIMAL_CONTAINER.
CALL_PARAMETER_NAME ZCL_DOG means the string literal “ZCL_DOG” is passed into constructor as a parameter.

Take record with index 6 in above screenshot for illustration

Method_type 2 means it is an instance method call.
CALLER_VARIABLE_NAME lo_dog_container means it is this variable which performs the current instance method.
METHOD_CLS_NAME ZCL_ANIMAL_CONTAINER means the instance variable lo_dog_container has class type ZCL_ANIMAL_CONTAINER.

METHOD_NAME ADD means the instance method being called has name “ADD”.
CALL_PARAMETER_NAME LO_CAT means the instance lo_cat is passed into instance method ADD.

(2) perform the real Covariance check based on regularized method call information generated in previous step

Since now the essential information for Covariance check, the generic type and concrete type are already available, it is ready to perform check.
(2.1) Covariance relevance check

I just loop every record and first check whether the current method call is relevant for Covariance check. I am using the assumption that a method call should only be checked against Covariance when the class of the instance which performs the call has been assigned with tag interface ZIF_COVARIANCE.

(2.2) Covariance check implementation by evaluate the relationship between generic type and concrete type

The evaluation is done in method below: if generic type and concrete type does not fulfill Covariance, syntax error is reported.

How to play around with this prototype by yourself

(1) Follow my blog Implement Custom Syntax Check in SAP GUI to setup necessary configuration create a new custom syntax check handler class ZCL_WB_CLEDITOR( source code could be found from my github mentioned above ).

(2) Create a class with any name and a new method with following source code:

  METHOD main.DATA(lo_dog_container) = NEW zcl_animal_container( iv_concrete_type = 'ZCL_DOG' ).
* concrete type must be ZCL_DOG or its subclass!DATA(lo_cat_container) = NEW zcl_animal_container( iv_concrete_type = 'ZCL_CAT' ).DATA(lo_cat) = NEW zcl_cat( ).DATA(lo_dog) = NEW zcl_dog( ).DATA(lo_toydog) = NEW zcl_toydog( ).* only dog or dog subclass instance is allowed for insertionlo_dog_container->add( lo_cat ).lo_dog_container->add( lo_dog ).lo_dog_container->add( lo_toydog ).ENDMETHOD.

(3) In Class builder under Form-based mode, press Ctrl+F2 and you should see two error messages for Covariance violation:

Further reading

I have written a series of blogs which compare the language feature among ABAP, JavaScript and Java. You can find a list of them below:

  • Lazy Loading, Singleton and Bridge design pattern in JavaScript and in ABAP
  • Functional programming – Simulate Curry in ABAP
  • Functional Programming – Try Reduce in JavaScript and in ABAP
  • Simulate Mockito in ABAP
  • A simulation of Java Spring dependency injection annotation @Inject in ABAP
  • Singleton bypass – ABAP and Java
  • Weak reference in ABAP and Java
  • Fibonacci Sequence in ES5, ES6 and ABAP
  • Java byte code and ABAP Load
  • How to write a correct program rejected by compiler: Exception handling in Java and in ABAP
  • An small example to learn Garbage collection in Java and in ABAP
  • String Template in ABAP, ES6, Angular and React
  • Try to access static private attribute via ABAP RTTI and Java Reflection
  • Local class in ABAP, Java and JavaScript
  • Integer in ABAP, Java and JavaScript
  • Covariance in Java and simulation in ABAP
  • Various Proxy Design Pattern implementation variants in Java and ABAP
  • Implement CGLIB in ABAP

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

Java的Covariance设计原理和SAP ABAP的模拟实现相关推荐

  1. java covariance_Java的Covariance设计原理和SAP ABAP的模拟实现

    I am the trainer of one standard course "Programming Language Concept" within SAP and ther ...

  2. SAP ABAP ADBC和Java JDBC的使用比较

    Horst Keller has already introduced ADBC in his blog ABAP Geek 15 – ADBC long times ago. And recentl ...

  3. SAP ABAP和Java里的弱引用(WeakReference)和软引用(SoftReference)

    Jerry前一篇文章 SAP ABAP一组关键字 IS BOUND, IS NOT INITIAL和IS ASSIGNED的用法辨析 介绍了在ABAP里判断引用变量是否包含了一个有效引用的关键字:IS ...

  4. 浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试

    文章目录 Java的静态代理 静态代理的优缺点 ABAP的静态代理 Spring AOP的动态代理 JDK动态代理的优缺点 CGLIB动态代理的优缺点 ABAP CGLIB的模拟实现 ABAP Pre ...

  5. SAP ABAP里存在Java List这种集合工具类么?CL_OBJECT_COLLECTION了解一下

    Jerry以前在工作中交替做着ABAP和Java开发时,总是在使用一种语言时,怀念另一种语言的便利之处,比如用ABAP开发时,怀念Java里以List为代表的功能强大,使用方便的集合工具类. List ...

  6. Jerry文章《浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试一文的源代码》

    原文链接 导航目录 工具类ZCL_ABAP_DYNAMIC_PROXY_FACTORY 工具类zcl_abap_cglib_tool Jerry Wang的ABAP专题文章 工具类ZCL_ABAP_D ...

  7. Java和SAP ABAP的异常处理

    Recently I am prepare an internal training and have been racking my brains to find a real example fo ...

  8. 从零开始来看一下Java泛型的设计

    引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除. 泛型基础 泛型类 我们首 ...

  9. SAP ABAP PA certification 培训笔记 part 4

    SAP ABAP PA certification 培训笔记 part 4 [@more@] 课前复习 Table key 由三部分构成 1. Components:组成key的字段 2. Seque ...

最新文章

  1. 基础知识——测试代码(七)
  2. lisp提取长方形坐标_求修改lisp程序,如何提取CAD中多个点的坐标,(本人想提取UCS坐标系)另外只需要提取X,Y值,不要Z...
  3. docker 安装MongoDB以及设置用户
  4. 苹果「热修复门」事件复盘、分析和展望
  5. USACO1.1 Broken Necklace (beads)
  6. oracle日期处理(一)
  7. echarts实现柱状图分页展示
  8. CodeForces - 1096D Easy Problem(线性dp)
  9. 虚拟机 VMware Workstation12 安装OS X 系统
  10. 【英语学习】【医学】Unit 02 The Brain and Its Functions
  11. 卸载sqlserver
  12. el表达式的转义字符。
  13. Impala介绍优缺点
  14. USACO 3.2.6 Sweet Butter 香甜的黄油(最短路)
  15. MVC 下 JsonResult 的使用方法(JsonRequestBehavior.AllowGet)
  16. 新建文本文档出现错误怎么办
  17. leedcode.21合并两个有序链表
  18. 自动化装配流水线转载运输机,3D图纸。图纸stp格式1g大小零件齐全
  19. JAVA计算机毕业设计高校教材征订管理系统Mybatis+源码+数据库+lw文档+系统+调试部署
  20. PHP技术开发微信公众平台

热门文章

  1. [leetcode]Subsets @ Python
  2. 闲话网名之“Johnny”
  3. 微软项目管理[EPM]数据库应用举例2: 取得一个项目的某大纲代码的值
  4. java.util.Date与 java.sql.Date两个包下Date的区别与联系
  5. EL表达式 参考手册
  6. maven项目添加jar包
  7. 用js控制video的src_百度知道
  8. idea整合mybatis错误
  9. 基于vue 2.X和高德地图的vue-amap组件获取经纬度
  10. [Unity3D]Unity3D游戏开发Lua随着游戏的债券(于)