Command–query separation principle [re: @mustuse as a function attribute]
Paul Backus
snarwin at gmail.com
Wed Oct 19 18:04:54 UTC 2022
On Wednesday, 19 October 2022 at 17:40:00 UTC, mw wrote:
> That's because you still consider the @mustuse attribute on
> each class level individually, if you think about the global
> system analysis as a whole, it will work, and consistently.
> Yes, what I proposed is transitive closure:
>
> /--------Base------\
> | | |
> Derived1 Derive2 Derive3
>
> If the programmer only manually marked Derive3.remove() as
> @mustuse, everything else (Base, Derived1 Derive2 Derive3)'s
> .remove() method will become @mustuse (as seen by the compiler
> internally).
The fundamental problem with this on a conceptual level (leaving
aside implementation issues) is that it completely breaks
modularity.
Suppose we have the following module layout:
--- base.d
module base;
class Base {
int fun() {...}
}
void doStuff(Base b)
{
import std.stdio;
writeln("Calling b.fun");
b.fun(); // ok - Base.fun is not @mustuse
}
--- derived.d
module derived;
import base;
class Derived : Base {
int fun() {...}
}
---
If I now decide to add @mustuse to Derived.fun, in the "derived"
module, and we apply your proposed global analysis, this will
cause a compilation error in the "doStuff" function in the "base"
module!
Note that the "base" module does not have any explicit dependency
on the "derived" module. It does not import it, or otherwise
refer to it in any way. In the real world, these two modules
might even be in separate dub packages.
More information about the Digitalmars-d
mailing list