AppSourceCop Error AS0023
A return type cannot be modified in external procedures
Description
A return type cannot be modified in external procedures.
Remarks
This rule validates that the return type of a public procedure has not been changed in a way that would break the compilation of dependent extensions. It is not allowed to change the return type of a public procedure that was published with a return type in a previous version. Adding a return type is allowed by this rule, but is validated by AS0102.
Note
This rule also covers the cases related to the TryFunction attribute which implicitly defines a Boolean return type.
How to fix this diagnostic?
Reverting the change will fix this diagnostic. If changing the return type is required, the recommended approach is to mark the procedure with the Obsolete attribute and introduce a new one with the desired return type. In a future version, once all dependent extensions have updated their code to not reference the obsolete procedure, you can remove it.
Code examples triggering the rule
In the following examples, version 1.0 of the extension defines a public procedure which returns an Integer.
Version 1.0 of the extension:
codeunit 50100 MyCodeunit
{
procedure MyProcedure(): Integer
begin
exit(5);
end;
}
Example 1 - Changing the return type of a procedure from Integer to Boolean
Version 2.0 of the extension:
codeunit 50100 MyCodeunit
{
procedure MyProcedure(): Boolean
begin
exit(true);
end;
}
In version 2.0, the return type of MyProcedure
has changed from Integer
to Boolean
. If a dependent extension used the return type of this procedure, this will lead to a compilation error similar to Cannot implicitly convert type 'Boolean' to 'Integer' (AL0122)
.
For example, the following extension compiles when depending on version 1.0, but fails to compile with version 2.0:
codeunit 50120 AnotherCodeunit
{
procedure AnotherMethod()
var
c: Codeunit MyCodeunit;
myInt: Integer;
begin
myInt := c.MyProcedure();
end;
}
Example 2 - Removing the return type of a procedure
Version 2.0 of the extension:
codeunit 50100 MyCodeunit
{
procedure MyProcedure()
begin
end;
}
In version 2.0, the procedure does not return anything anymore. If a dependent extension used the return type of this procedure, this will lead to a compilation error similar to Cannot implicitly convert type 'None' to 'Integer' (AL0122)
.
For example, the following extension compiles when depending on version 1.0, but fails to compile with version 2.0:
codeunit 50120 AnotherCodeunit
{
procedure AnotherMethod()
var
c: Codeunit MyCodeunit;
myInt: Integer;
begin
myInt := c.MyProcedure();
end;
}
Example 3 - Removing the return type of a procedure and adding a TryFunction attribute
Version 2.0 of the extension:
codeunit 50100 MyCodeunit
{
[TryFunction]
procedure MyProcedure()
begin
exit(true);
end;
}
In version 2.0, the procedure now returns a Boolean value because it is marked as a TryFunction. This scenario would lead to the same compilation errors than mentioned in Example 1 above.
Code examples not triggering the rule
In the following examples, the version 1.0 of the extension defines a procedure which does not have a return type.
Version 1.0 of the extension:
codeunit 50100 MyCodeunit
{
procedure MyProcedure()
begin
end;
}
Example 1 - Adding a return type to a procedure
Version 2.0 of the extension:
codeunit 50100 MyCodeunit
{
procedure MyProcedure(): Boolean
begin
exit(true);
end;
}
In version 2.0, the procedure MyProcedure
is now returning a boolean. However, it does not break the compilation of dependent extensions because they were not consuming the return type of the procedure.
Important
Adding a return type to a procedure is a runtime breaking changes. Dependent extensions that are referencing the procedure must be recompiled in order to avoid experiencing issues at runtime. For on-premises installations this can be done using Repair-NavApp. For SaaS, we do not allow adding return types, this is validated by the rule AS0102.
Example 2 - Adding a TryFunction attribute to a procedure
Version 2.0 of the extension:
codeunit 50100 MyCodeunit
{
[TryFunction]
procedure MyProcedure()
begin
exit(true);
end;
}
In version 2.0, the procedure is now marked as a TryFunction. This means that this return type has implicitly been changed to Boolean. Similarly, it is possible to add a TryFunction attribute on a function that already returned a Boolean.
Related information
AppSourceCop Analyzer
Get Started with AL
Developing Extensions