Dynamic method dispatch in X++

X++ is statically typed language, right? Still, sometimes we need to use it in a dynamic manner…

The most common case is the need to call methods defined on a form. You can’t do it with static types – forms are technically instances of SysSetupFormRun class, which obviously doesn’t include methods you added to your form. You also can’t cast the reference to the type of the form, because forms are not types in X++. From AX perspective, forms don’t have custom methods added at design time; methods are added dynamically to a SysSetupFormRun instance based on the form definition. So we also have to call them dynamically.

The solution is to cast the reference to Object type. You might expect that X++ compiler would allow you to call only methods defined in Object class, but that’s not the case. Compiler actually won’t check any methods called on a reference of Object type and AX will try to call them at runtime. This is valid, compilable X++ code, which will obviously fail:

Object o = new Object();
// throws exception "Object object does not have method 'nonexistingMethod'"
o.nonexistingMethod();

For comparison, the same code wouldn’t compile in C#, because C# uses static typing even in this case. You could get similar behavior by using dynamic type:

dynamic o = new Object();
// throws RuntimeBinderException "'object' does not contain a definition for 'nonexistingMethod'"
o.nonexistingMethod();

The same approach can be used to call form methods. For example, you want to call executeCustomLogic() method on the caller form:

Object callerForm = element.caller();
callerForm.executeCustomLogic();

This works and it’s sometimes useful. But you must be aware of consequences. Because there is no compile-time control, you won’t get any compilation error if the method doesn’t exist (because somebody renamed it, for example). Dynamic calls are also not included in cross-references, because compiler simply doesn’t know what you call. This has significantly negative impact on maintainability of your code. With forms, you can check whether a form has a specific method by calling formHasMethod(), but it’s still just a runtime check.

These problems are serious, therefore you should avoid dynamic typing in X++ whenever possible. Instead of calling form methods, for example, you could provide a class instance as caller or parmObject, cast it to the appropriate class or interface and call methods in type-safe way.