Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 

Introduction

If you've worked with OO ABAP for a while, you've probably hit this situation: you define an interface with a handful of methods, and suddenly every single class that implements it is forced to write a method body even for stuff that class doesn't care about. Multiply that across a dozen implementing classes and you end up with a pile of empty, do-nothing method stubs just to keep the compiler happy.

ABAP actually has a clean way around this, and it's one of those features that doesn't get talked about enough, the DEFAULT IGNORE and DEFAULT FAIL additions on interface method declarations. Once you know about them, you'll wonder how you lived without them.

Picture an interface for handling pricing logic. Something like:

INTERFACE zif_pricing. 
 METHODS check_pricing_needed. 
 METHODS run_calculation 
   DEFAULT IGNORE. 
 METHODS fetch_base_amount 
   RETURNING VALUE(rv_amount) TYPE p 
   DEFAULT FAIL. 
ENDINTERFACE.

Not every class that plugs into zif_pricing will need all three methods. Maybe check_pricing_needed is genuinely required everywhere, but run_calculation only matters for a subset of classes, and fetch_base_amount is something you want classes to be forced to think about if they ever try to use it.

Rather than making every implementer write empty stubs, you can tell ABAP what should happen at runtime if a method is left unimplemented. That's what these two additions do, they shift the "what if this isn't implemented" decision from compile-time enforcement to a runtime behavior you control.

DEFAULT IGNORE: silently do nothing

Tag a method with DEFAULT IGNORE and here's the deal: if a class skips implementing it, calling that method just... does nothing. No error, no dump, nothing. It behaves exactly as if someone had written an empty METHOD ... ENDMETHOD. block. Any returning parameter just comes back with its initial value, and the program keeps going like nothing happened.

This is great for the genuinely optional stuff things where "not implemented" and "nothing to do here" mean the same thing. Logging hooks, audit trail updates, optional enhancement points, extra notifications anywhere a no op is a perfectly acceptable outcome.

DEFAULT FAIL: blow up loudly instead

DEFAULT FAIL is the opposite philosophy. If the implementing class doesn't provide a body for that method, calling it raises a runtime exception, specifically CX_SY_DYN_CALL_ILLEGAL_METHOD. Leave that exception unhandled and you'll get a short dump (CALL_METHOD_NOT_IMPLEMENTED).

This sounds harsh until you think about why you'd want it. There's a real difference between "this method isn't relevant for this class" and "this class genuinely needs this logic but someone forgot to write it." DEFAULT FAIL exists for the second case it converts a silent gap in your business logic into something that screams at you the moment it's hit, instead of quietly limping along and producing wrong results downstream.

Tax calculations, price determination, approval logic, validation anything where skipping the logic isn't a valid outcome, just a bug waiting to be found is a good candidate for DEFAULT FAIL.

Walking through it

Define the interface with the optional methods marked accordingly:

INTERFACE zif_pricing.
  METHODS check_pricing_needed.
  METHODS run_calculation
    DEFAULT IGNORE.
  METHODS fetch_base_amount
    RETURNING VALUE(rv_amount) TYPE p
    DEFAULT FAIL.
ENDINTERFACE.

Implement it in a class, but only bother with the mandatory method:

CLASS zcl_pricing DEFINITION.
  PUBLIC SECTION.
    INTERFACES zif_pricing.
ENDCLASS.

CLASS zcl_pricing IMPLEMENTATION.
  METHOD zif_pricing~check_pricing_needed.
    " actual business logic goes here
  ENDMETHOD.
ENDCLASS.

Notice there's no METHOD zif_pricing~run_calculation or METHOD zif_pricing~fetch_base_amount anywhere in this class and that's completely fine. The compiler only insists on an implementation for methods that don't carry a DEFAULT addition.

Call the IGNORE method and watch nothing bad happen:

DATA(lo_pricing) = NEW zcl_pricing( ).
lo_pricing->zif_pricing~run_calculation( ).

Since this one was never implemented but is marked DEFAULT IGNORE, the call just passes through quietly same as calling an empty method.

Call the FAIL method and you'll get an exception:

DATA(lv_amount) = lo_pricing->zif_pricing~fetch_base_amount( ).

Because fetch_base_amount is DEFAULT FAIL and was never implemented, this line throws CX_SY_DYN_CALL_ILLEGAL_METHOD. Leave it unhandled and the program dumps.

Handle it properly instead of letting it dump:

TRY.
    DATA(lv_amount) = lo_pricing->zif_pricing~fetch_base_amount( ).
  CATCH cx_sy_dyn_call_illegal_method INTO DATA(lx_err).
    MESSAGE lx_err->get_text( ) TYPE 'I'.
ENDTRY.

Wrapping the call in a TRY/CATCH lets you turn that hard failure into a controlled message instead of a dump in production.

Why bother with DEFAULT FAIL at all — isn't IGNORE always safer?

It feels safer on the surface, but that's actually the trap. Say you've got:

METHODS send_notification DEFAULT IGNORE.

If a class forgets to implement this, calling send_notification( ) just silently does nothing. No email goes out, no alert fires and the calling code has no idea anything went wrong. That's the kind of bug that sits undetected for months because everything looks fine from the outside.

Mark it DEFAULT FAIL instead, and a forgotten implementation gets caught the first time it's actually exercised, not three releases later when someone's wondering why customers never got their notification emails.

Rule of thumb for picking one

Go with IGNORE when "not implemented" and "nothing happens" are an acceptable, sensible default logging, auditing, optional enrichment, extension hooks.

Go with FAIL when skipping the logic would produce incorrect or incomplete business behavior pricing, tax, approvals, workflow triggers, validations. Anywhere being wrong silently is worse than crashing loudly.

A few things to keep in mind

  • These additions only apply inside interface declarations you can't slap DEFAULT IGNORE or DEFAULT FAIL on a regular class method.
  • Constructors and test methods can't be made optional this way.
  • Both work fine whether the method is instance bound or static.
  • They're also usable in BAdI interface definitions, which is honestly where I think they shine the most BAdIs love having a long list of methods where only a couple are relevant to any given implementation.

Bottom line

DEFAULT IGNORE and DEFAULT FAIL give you a way to design genuinely flexible interfaces without sacrificing safety. Instead of forcing every implementer to write boilerplate empty methods, you decide upfront, right in the interface definition, what "not implemented" should mean for each method a harmless no op, or a loud, catchable failure. Used well, it keeps your interfaces lean and your bugs visible instead of buried.

Labels in this area