Back to all posts

Booleans in ABAP: From 'X' and Space to xsdbool

André Schärpf

ABAP does not have a boolean type. Not in classic ABAP, not in ABAP Objects, and not in ABAP Cloud. After more than 40 years, the language still represents true and false with a single character: 'X' for true, a space for false.

What it does have is a long trail of conventions, type pool constants, built-in functions, and workarounds that try to make this bearable. Some of them work well. One of them is subtly broken in a way that most developers never notice until it causes a real bug. This post covers all of them.

The old way: 'X' and space

Before any of the modern helpers existed, ABAP developers used CHAR 1 fields and the convention that 'X' means true and ' ' (space) means false. The XFELD data element in the ABAP Dictionary formalized this for screen fields and function module parameters.

DATA lv_found TYPE c LENGTH 1.

IF sy-subrc = 0.
  lv_found = 'X'.
ELSE.
  lv_found = ' '.
ENDIF.

IF lv_found = 'X'.
  " ...
ENDIF.

This works. It's also unreadable to anyone who doesn't already know the convention, and easy to break with a typo. There is nothing in the language preventing lv_found = 'Y' or lv_found = '1', and the compiler will not complain.

Type pool ABAP: naming the convention

The type group ABAP introduced named constants for the boolean convention:

NameTypeValueMeaning
abap_boolc LENGTH 1(type only)The standard boolean substitute
abap_trueabap_bool'X'True
abap_falseabap_bool' 'False
abap_undefinedabap_bool'-'Third state, for rare three-value logic

The old TYPE-POOLS: abap. statement is obsolete. Since Release 7.0 EhP2, a type group is loaded automatically when one of its elements is first accessed.

DATA lv_found TYPE abap_bool.
lv_found = abap_true.

IF lv_found = abap_true.
  " ...
ENDIF.

This is the same CHAR 1 underneath, but it reads like actual code instead of a magic character. The initial value of abap_bool is ' ' (space), which equals abap_false. So a freshly declared boolean variable defaults to false without any explicit assignment.

abap_undefined exists for edge cases where a three-value boolean is needed. SAP's own documentation calls it "only useful and recommended in exceptional cases."1 In practice, most ABAP code never touches it.

boolc: the first attempt

By Release 7.0 EhP2 (7.02), ABAP had boolc(), the first built-in function that converts a logical expression into a value:

DATA(lv_flag) = boolc( sy-subrc = 0 ).

One line instead of five. The problem is the return type.

boolc() returns string, not c LENGTH 1. The values are a one-character string "X" for true and a one-character string " " (containing a single space) for false. This looks harmless, but it breaks comparisons with abap_true and abap_false in a way that is genuinely difficult to debug.

The gotcha

IF boolc( 1 = 2 ) = abap_false.
  WRITE 'This should execute, but it does not.'.
ENDIF.

The expression 1 = 2 is false. boolc() returns the string " ". abap_false is c LENGTH 1 with value ' '. When the runtime compares a string with a c value, it converts the c to string. During that conversion, trailing blanks are stripped. A single space becomes an empty string "". The comparison becomes " " = "", which is false.

So boolc( 1 = 2 ) = abap_false evaluates to false, even though the expression is false. The check silently goes to the ELSE branch and nobody gets an error.

The same problem affects IS INITIAL. A string containing a space character is not initial, so boolc( 1 = 2 ) IS INITIAL is also false.

The asymmetry that makes it worse

Here is the part that makes this bug particularly dangerous: the true case works fine.

IF boolc( 1 = 1 ) = abap_true.
  WRITE 'This works correctly.'.
ENDIF.

boolc() returns string "X". abap_true is c value 'X'. Converting 'X' to string gives "X" (no trailing blank to strip). The comparison succeeds.

The gotcha only manifests for the false case. If you test your code with a few happy-path scenarios and they all pass, you will never see the bug. It only surfaces when the expression evaluates to false and you compare the result. This is exactly the kind of thing that passes unit tests on the first try and then causes production issues weeks later.

The ABAP compiler now warns about this. If you use boolc() with inline declaration, you get:

"LV_FLAG" is given the technical type "STRING" (with truth values X and ). To get the technical type "C" (with values 'X' and '') use the function "XSDBOOL" instead of "BOOLC".

The compiler is right. Use xsdbool.

xsdbool: the fix

ABAP 7.40 SP08 introduced xsdbool() specifically to fix the comparison problem:

DATA(lv_flag) = xsdbool( sy-subrc = 0 ).

The return type is c LENGTH 1, specifically the ABAP Dictionary type XSDBOOLEAN. The values are 'X' and ' ', directly compatible with abap_bool, abap_true, and abap_false.

All the things that break with boolc work correctly with xsdbool:

" Comparison with abap_false: works
IF xsdbool( 1 = 2 ) = abap_false.
  WRITE 'Correct.'.
ENDIF.

" IS INITIAL on false result: works
DATA(lv_false) = xsdbool( 1 = 2 ).
IF lv_false IS INITIAL.
  WRITE 'Correct.'.
ENDIF.

The name comes from XSDBOOLEAN, which was originally an ABAP Dictionary type for XML Schema Definition mappings. Horst Keller, SAP's Knowledge Architect for the ABAP language, noted that the type was "reused here for quite another purpose."2 The name stuck, cryptic as it is.

Serialization

The XSDBOOLEAN type is also handled specially by CALL TRANSFORMATION. In asXML and asJSON, an XSDBOOLEAN field serializes as the actual words true and false:

DATA lv_flag TYPE xsdboolean VALUE abap_true.

CALL TRANSFORMATION id
  SOURCE flag = lv_flag
  RESULT XML DATA(lv_xml).
" Produces: <FLAG>true</FLAG>

A plain abap_bool field does not get this treatment. It serializes as the raw character value:

DATA lv_flag TYPE abap_bool VALUE abap_true.

CALL TRANSFORMATION id
  SOURCE flag = lv_flag
  RESULT XML DATA(lv_xml).
" Produces: <FLAG>X</FLAG>

If you use transformations to produce or consume XML or JSON, this distinction matters. Deserialization also accepts "1" and "0" as input for XSDBOOLEAN. Invalid values raise CX_SY_CONVERSION_NO_BOOLEAN.

Predicative method calls

The same release (7.40 SP08) introduced predicative method calls, which let you use a method directly in an IF condition without comparing its return value:

" Before 7.40 SP08
IF lo_validator->is_valid( ) = abap_true.
  " ...
ENDIF.

" After 7.40 SP08
IF lo_validator->is_valid( ).
  " ...
ENDIF.

The compiler treats this as IS NOT INITIAL. Any non-initial return value is truthy. This works for any return type, but it makes the most sense for methods that return abap_bool, where the initial value (space) is false and the non-initial value ('X') is true.

Names like is_, has_, or can_ read naturally here:

CLASS lcl_document DEFINITION.
  PUBLIC SECTION.
    METHODS is_archived
      RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.

CLASS lcl_document IMPLEMENTATION.
  METHOD is_archived.
    result = xsdbool( mv_status = 'A' ).
  ENDMETHOD.
ENDCLASS.

The combination of xsdbool inside the method body and a predicative call at the call site gives clean code on both sides.

COND and SWITCH

Before xsdbool existed, ABAP 7.40 SP02 introduced the COND and SWITCH constructor operators. You can use them for boolean assignments:

" COND: general conditional
DATA(lv_flag) = COND abap_bool( WHEN lv_amount > 0
                                 THEN abap_true
                                 ELSE abap_false ).

" SWITCH: discrete value mapping
DATA(lv_editable) = SWITCH abap_bool( lv_mode
                      WHEN 'E' THEN abap_true
                      WHEN 'C' THEN abap_true
                      ELSE abap_false ).

Both produce the same abap_bool result. SWITCH reads better when you are mapping specific values; COND handles arbitrary logical expressions.

In practice, xsdbool() replaces most COND abap_bool() patterns with less code:

" Verbose
DATA(lv_flag) = COND abap_bool( WHEN lv_amount > 0
                                 THEN abap_true
                                 ELSE abap_false ).

" Equivalent, shorter
DATA(lv_flag) = xsdbool( lv_amount > 0 ).

COND still has a place when the condition involves multiple WHEN branches or when the true/false values are not standard abap_true/abap_false.

The boolean zoo

ABAP systems tend to accumulate multiple boolean-like DDIC objects over time. Some overlap at the value level, but not all of them are interchangeable.

ObjectTrueFalseOtherNotes
ABAP_BOOL (type pool)'X'' ''-' (undefined)Recommended for ABAP programs
XSDBOOLEAN (DDIC)'X'' 'Used by xsdbool(), mapped to true/false in asXML/asJSON
BOOLEAN (DDIC)'X''-'' ' (unknown)Inverted: space means unknown, not false
XFELD (DDIC)'X'' 'Classic checkbox field
BOOLE / BOOLE_D (DDIC)'X'' 'Another standard true/false pair
XFLAG (DDIC)'X'' ''.'Old UI-oriented oddity: dot means radio button

This is not an exhaustive catalog, just a best-of of the boolean-like types you are likely to meet in standard ABAP work. Once you start digging through specific packages, customer namespaces, or older custom code, you will usually find even more variants, and some of them are stranger than the ones listed here.

The BOOLEAN data element deserves special attention. Created in 1995 and referenced by thousands of classes across the SAP system, its semantics are the opposite of abap_bool: space does not mean false, it means "unknown." False is represented by a dash. Mixing BOOLEAN and abap_bool without checking which convention applies is a reliable way to introduce bugs.

The abap-cleaner team acknowledged this problem but determined that automated replacement is impossible: "this zoo of Boolean types really is a pain!"3 Variables may receive values from function modules with incompatible types, and without full semantic analysis, a conversion tool could silently break working code.

If you need a DDIC type that should behave like a real boolean in transformations, use XSDBOOLEAN. For plain program variables and method parameters, use abap_bool.

And then there are the true outliers. CHANGEDOCUMENT_PREPARE_TABLES, a function module from 1995 that compares two internal tables, returns its result as 'T' for identical and 'F' for different. Not X and space, not 1 and 0, not true and false. Just the letters T and F, because apparently someone decided that was a reasonable convention for a single function module.

I have a vivid memory of debugging a change document implementation during vocational training. I was sitting in class, laptop open, and the code was not working. After what felt like an unreasonable amount of time, I realized the function module was returning 'T' and 'F' instead of anything I had expected. I must have reacted visibly annoyed enough that the teacher stopped mid-sentence to check what was going on. That is the kind of experience that makes you want a proper boolean type in the language.

Enum booleans

ABAP 7.51 introduced enumerated types. You can define a type-safe boolean:

TYPES: BEGIN OF ENUM t_bool BASE TYPE abap_bool,
         false VALUE IS INITIAL,
         true  VALUE 'X',
       END OF ENUM t_bool.

DATA lv_flag TYPE t_bool.
lv_flag = true.    " OK
lv_flag = 'X'.     " Syntax error
lv_flag = 'Y'.     " Syntax error

Unlike abap_bool, where any single character can be assigned without complaint, an enum variable only accepts the defined enum values. The compiler catches invalid assignments at syntax check time.

The trade-off is compatibility. Enum types are local ABAP language types, not DDIC types. They cannot be used directly for database fields, classic function module parameters, or Dynpro screen fields. For internal logic where type safety matters and the boolean does not cross system boundaries, they work well. For APIs and interfaces, abap_bool with xsdbool() remains the pragmatic choice.

What to use today

For ABAP 7.40 SP08 and later, including ABAP Cloud:

  • Declare boolean variables with TYPE abap_bool
  • Assign using xsdbool() for logical expressions
  • Compare with abap_true and abap_false, not 'X' and ' '
  • Use predicative method calls for boolean-returning methods
  • Use XSDBOOLEAN when you need proper JSON/XML serialization
  • Do not use boolc()
" Declaration
DATA lv_valid TYPE abap_bool.

" Assignment from expression
lv_valid = xsdbool( lo_document->get_status( ) = 'ACTIVE' ).

" Comparison
IF lv_valid = abap_true.
  " ...
ENDIF.

" Predicative method call
IF lo_document->is_archived( ).
  " ...
ENDIF.

The language still does not have a boolean type, and probably never will. But with xsdbool, predicative method calls, and abap_bool, the gap is small enough that it rarely gets in the way.

Further reading

Sources

Footnotes

  1. SAP Help, Data Objects for Truth Values

  2. Horst Keller, ABAP News for 7.40, SP08 - Logical Expressions

  3. SAP abap-cleaner, Issue #260: Replace bad boolean data elements