Reputation: 2071
Context:
I'm java programmer and reading Uncle Bob Agile Software Development. Regarding ISP Interface Segregation Principle there is given an argument which I understand as:
Lets have:
interface Service {
function doA();
}
class ServiceImpl implements Service {...}
class ServiceClient {
// ServiceImpl is injected; eg either through constructor or setter
private Service service;
function useOnlyDoA() {
service.doA();
}
}
And now, if interface Service changes, e.g. method doB()
is added, then all dependent classes e.g. ServiceClient
have to be recompiled, even if they don't use added method! (really??)
I lived in conviction that regarding java if ServiceClient
is in package e.g. client.jar
, interface Service
in service.jar
and ServiceImpl
in impl.jar
, then client.jar
doesn't have to be recompiled and rebuild if it doesn't use new methods from Service interface and it can be used together with new versions of service.jar
and impl.jar
. It seems to me that things go this way in java.
Is it other in eg c++ or some other languages?
Possibly in c++ much more is broken, eg https://stackoverflow.com/a/4033900/1423685
To make it clear:
I'm not asking about recompiling class implementing changed interface (this is obvious, it class has to implement new added method). But I am asking if I have to recompile class ServiceClient which is using this interface even when class isn't using new added methods. Possibly in c++ BC changes and client really has to be recompiled, but it seems to me that not in java.
Edit:
I implemented a test in java. 4 jars:
public interface Service
public class ServiceImpl implements Service
ClientOfService
taking Service
as a constructor parameter, uses this service in it's doA()
method
public static void main(String[] args) {
Service service = new ServiceImpl();
ClientOfService clientOfService = new ClientOfService(service);
System.out.println("App.main() :: calling clientOfService.doWorkCallingDoAFromService");
clientOfService.doWorkCallingDoAFromService();
System.out.println("App.main() :: end of main");
}
The main in App run successfully after change of interface.jar and implementation.jar (I added some unused methods and removed one old method).
So the challenge is how to change interface (of course without changing doA()
method declaration) and implementation to stop it running successfully? Is it possible? If so, how?
Upvotes: 8
Views: 1159
Reputation: 73376
Yes, if you change the interface, you need to recompile the classes that implement it in Java and in C++. This has several reasons, among others:
vtable
if doB() is virtual), and verify if another member function with the same signature but in another base class is not hidden by the newly created one. The whole thing of the ISP is to avoid such situations. So if doB()
has in reality nothing to do with this interface, you'd better go for a segregated interface with just doB()
, and change/recompile only the classes that need to implement it.
Edit: The same principle applies to classes that use the interface. Some of the arguments may of course be implementation dependent:
Upvotes: 8
Reputation: 64845
For which other languages it it true, and for which isn't?
This is really implementation-specific characteristic rather than language characteristic.
Recompilation is usually needed for language implementations that compiles member access on interfaces to memory addresses or array indexes of a function table. This is how most static language compilers are implemented. Most Java and C implementations would fall under this category.
Recompilation wouldn't be necessary for languages implementation that compiles member access to dictionary lookup (so that it uses the function name for the lookup, rather than a substitute index). This is how most dynamic languages compilers are implemented. For example, most Python implementations don't need to recreate .pyc files if classes in another file changes its interface.
So the main divide is between static and dynamic language. There are exceptions of course. It's possible in some static language to ensure that any new additions are appended to the function table, so existing code that code that uses the old indexes will still work. For library authors in most static languages, it is an important consideration to only change interfaces in ways that preserves binary compatibility if the language implementation allows for it.
Upvotes: 0