equivariant functions

Robert Fraser fraserofthenight at gmail.com
Wed Oct 15 01:22:27 PDT 2008


Benji Smith wrote:
> Andrei Alexandrescu wrote:
>> Benji Smith wrote:
>>> I really don't see what all the fuss is about with the equivariance 
>>> stuff, except that it introduces a lot of confusing rules to fix the 
>>> holes in the (already complex and confusing) const system.
>>
>> Please stop perpetuating misunderstanding and apprehension about the 
>> const system through statements strong on opinion and vague on detail. 
>> If you're willing to mention holes, complexity, and confusion about 
>> the const system, please explain where the holes are, where the 
>> complexities lie, and what aspects you are confused about. Suggestions 
>> for fixing said issues would also be welcome.
> 
> Fair enough. Here are the reasons I describe the const system as "complex":
> 
> * Comparable code without const qualifiers contains quantatitively fewer 
> semantic constructs than code that uses those qualifiers. Smaller 
> function prototypes are easier to read and comprehend:
> 
>    char[] join(char[] str2, char[] str2) { ... }
> 
>    const(char)[] join(const(char)[] str1, const(char)[] str1) { ... }
> 
> * Nestable const type constructors require me to keep a more detailed 
> mental model of the type system. Am I using a "const(char)[]" or a 
> "const(char[])"?
> 
> * Remembering the difference between "const" and "invariant" requires 
> more mental energy than using a system (D1) where such distinctions 
> don't exist.
> 
> * The idea that "const" is a supertype of "mutable" and "invariant" is 
> utterly bizarre to me, since it violates the "is a" rule of type 
> hierarchies. I understand that, for the sake of overloading, both 
> "mutable" and "invariant"  can be implicitly cast to "const", but the 
> other implications of that relationship are beyond my grasp at the moment.
> 
> * The transitivity of const qualifiers requires me to consider not just 
> the object I'm passing around, but the references to other objects 
> contained within the const-qualified object.
> 
> * Both "const" and "invariant" can apply to value-type objects. But 
> "const" doesn't make any sense in that context, so in my mind I have to 
> use the "invariant" concept instead whenever applying the concept to a 
> primitive value.
> 
> * The equivariance proposal, at least in some of its forms, requires me 
> to imagine the existence of implicit typedefs at the function-call site, 
> and to know that the declared type in my method signature might not be 
> the actual type of the arguments received by the function.
> 
> The "holes" I described in the const system are the symptoms being 
> addressed by the equivariance proposal. Without equivariance, the const 
> system sometimes requires verbatim duplication of code within function 
> bodies whose only difference is their signature. Without the const 
> system, the equivariance proposal wouldn't be necessary.
> 
> And the reason I describe the const system as "confusing"?
> 
> Because it confuses me.
> 
> I understand some of the allure of having a robust, provably correct 
> const system. Automatic memoization would be cool. Automatic parallel 
> execution would be nice. And, in theory, it'd be nice to avoid errors 
> that occur when a piece of code modifies a piece of data that it shouldn't.
> 
> But in my experience (using languages that lack any sort of const 
> system, except for enum-style declarations), it just doesn't matter 
> much. When I need memoization or parallel execution, I write the code 
> explicitly. And when I need an immutable object, I design its interface 
> to make external mutation impossible (see also: java.lang.String).
> 
> It's indisputable that the D2 const system is measurably more complex 
> than the D1 const system.
> 
> For me, the cost of that complexity significantly outweighs the benefit.
> 
> --benji

In my ideal language, I'd like a const system where instead of the 
instances of types (primitive or not) being qualified, the types 
themselves were. So a "const class" or "const struct" would mean that 
every instance of that type is constant after construction.

So you'd have:
---
class MutableType
{
     int x;
     this(int _x) { this.x = _x; }
}
const class ConstType {
     int x;
     this(int _x) { this.x = _x; }
}
MutableType m = new MutableType(5);
ConstType c = new ConstType(5);
m.x = 10; // OK
c.x = 10; // ERROR
---

All classes that extend a const class would also need to be const. As 
for primitives, they would either be manifest-constant or mutable like 
in D1. This covers most common use cases very well (except for constant 
arrays... hmmmm....) and is easy for the user to understand. Plus, a 
"const class" under this system is the same as an "invariant" under the 
current system, so no synchronization required. Making invariant classes 
(classes that are final and where all members are final) are a common 
design pattern in Java.

But I'm dreaming here since Walter seems dead-set on this system.



More information about the Digitalmars-d mailing list