3

When you define an abstract method of a class as public or global, an attempt to change the access modifier to protected or private when overriding the method produces a compile time error:

Cannot reduce the visibility of method: ...

Similarly for interface methods,

Overriding implementations of global or public interface methods must be global or public: ...

But why is it that Apex allows you to use the public and global access modifiers interchangeably?

Are there useful managed package design patterns that involve making a global method public for some subtypes of your class/interface?


Here is an example that the compiler allows:

An abstract class SuperClass

global abstract class SuperClass
{
    global abstract void superClassMethod();    
}

An interface MyInterface

global interface MyInterface{

    void interfaceMethod();

}

A subclass that implements the interface SubClass1

global class SubClass1
       extends SuperClass
       implements MyInterface
       {

    // Note the access modifiers    
    global override void superClassMethod(){ }

    global void interfaceMethod(){ }

}

Another subclass that implements the interface SubClass2

global class SubClass2
       extends SuperClass
       implements MyInterface
       {

    // Note the access modifiers
    public override void superClassMethod(){  }

    public void interfaceMethod(){  }

}
2

global and public are essentially synonyms. The only difference is that global methods and interfaces can be accessed outside of the package's code. I can see this as useful in a few situations. Perhaps you want to define an interface that can be used in a global context (e.g. to provide plugin access points for your subscribers), but you also have classes that you want to protect from being called externally that happen to implement these interfaces.

This can be advantageous for two primary reasons: (1) global methods can't be "deleted", so declaring something global might limit future development, and (2) public methods can't be called outside the package. I'm sure someone somewhere out there is using this pattern, but I'd also be willing to bet that this is probably an incredibly rare use case. Without someone at Salesforce explicitly mentioning why the two are interchangeable, the best we can do is guess as to the original intent.

I suspect that this is intentional, though, because it makes sense that you'd want to be able to have a global default implementation yet be able to hide specific sub-implementations that clients shouldn't call directly. Either way, I would carefully consider the possible effects of mixing the two. Generally speaking, if it's not client-callable code, don't make it global. Always provide the minimum access level necessary that works for the intended design.

  • I don't have any ideas on how to mix the two annotations at this point, but I am curious what they might be. I was mainly just thinking that an accidental public annotation on a subclass would introduce run-time errors that can only be detected by running code in an installing org, and it would have been nice for the Apex compiler and unit tests in just the managed package developer org to guarantee that these errors wouldn't occur. – martin Mar 2 '18 at 12:49
  • @martin As far as I recall, doing so should not introduce errors, but I still wouldn't do it unless I absolutely thought it was necessary. – sfdcfox Mar 2 '18 at 13:39
1

I thought of a possible use case, a hook method.

The idea here is that you have a global virtual class that you want the installing orgs to be able to extend, with a global method that has required functionality that you don't want installing orgs to be able to completely overwrite.

When you define the super class, the virtual method needs to be global so that it can be extended by code outside of the namespace:

global virtual class SuperClass{

    global void go(){
        // essential code that needs to be called 
        optionalProcessing();
    }

    global virtual void optionalProcessing(){  }

}

However, if you also define a subclass in the package, you don't want the method to be global since it is already being called by the primary method, and shouldn't be called directly anyways.

global class SubClass
       extends SuperClass
{

    public override void optionalProcessing(){ System.debug(''); }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.