June 24, 2007
Hmm last days I've noticed chaos going on in D comunity caused by D branches. I've written a small post about it on my devblog http://petermodzelewski.blogspot.com/ with some solution proposals. I don't want to play smartass but if D news become messy - D can lose its chance to be considered serious by professional developers. I hope my article can help a little with minimizing the chaos caused by the branches.


June 24, 2007
Martin Howe wrote:
> After reading the articles by Walter referred to recently, I'm less confused that I was, but would still appreciate some further explanation.
> 
> So should "const foo bar = baz" be an error if foo is a value type, on the basis that one should be using "invariant" or maybe final? It it safe to have two things const/invariant that become identical depending on type?

For value types, there's no difference between const, final, and invariant. So it's not an error.

This is probably the most confusing part of the whole deal, and there's no way around it except by making all value types into reference types (ugh) or vice versa (but we've progressed beyond C).

> And does "final" exist *solely* so that you can approximate "invariant" for objects as well as for structs and scalars? I can see its use when you want something to be invariant but with the stipulation that it must exist in memory and have an address. In which case, why have final vs invariant at all, rather than having final be, for example, "weak invariant" or "stored invariant" or something like that? From here, final just looks *semantically* like "a poor man's invariant".
> 
> 

Not at all. A final variable cannot be reassigned; the reference is const, but the data is mutable.

So:
---
class Foo {
   int _bar;
   public void bar(int value) { _bar = value; }
}

final Foo foo = new Foo();
foo.bar = 5; // legal -- I'm not touching the reference
foo = new Foo(); // fails -- foo was already assigned
---
June 24, 2007
Bruno Medeiros wrote:
> 
> I agree. Since in D, compile time values cannot be altered at compile time, then any compile time value is immutable/invariant. Thus const-as-storage-class is the same as invariant-as-storage-class and those concepts should be cleared up.

The storage class vs. type constructor issue should be cleared up in general.  From the documentation, I had originally (falsely) assumed that invariant was a storage class only, when in reality the issue is much more simple.  So far as I can tell, as type constructors, 'invariant' means the data will not change, period, 'const' means that the data can not be changed through the const-qualified reference, and 'final' means the reference cannot be reassigned once set.  As storage classes, 'const' and 'invariant' mean exactly the same thing, and I'm still not entirely sure if there is a storage class interpretation of 'final'.

As far as their application to non-reference variables is concerned, I think the overlap is unavoidable: they all mean effectively the same thing.


Sean
June 24, 2007
Bruno Medeiros wrote:
> Sean Kelly wrote:
>>
>>>> I can appreciate that 'invariant' may be of tremendous use to the compiler, but I balk at the notion of adding language features that seem largely intended as compiler "hints."
>>>
>>> It's a lot more than that. First, there's the self-documenting aspect of it. Second, it opens the way for functional programming, which can be of huge importance.
>>
>> Could you explain?  I've been trying to determine how I would write a library using these new features, and so far, 'invariant' simply seems more an obstacle to maintainability (because of the necessary code duplication), than it is an aid to programming.
>>
> 
> In which situation does having 'invariant' lead to code duplication? I can see the common situation where you have class getter methods, or other similiar methods, but even without 'invariant' and only with const and non-const you have that problem.

Let's say I am writing a linear search routine for arrays.  The most obvious implementation would accept that array as 'const', but it may be more optimal to use 'invariant'.  Since not all searchable arrays will be invariant however, both implementations must exist.  That said, a template function could likely handle both situations with the same code, and hopefully it will be uncommon to want virtual class routines that take both types of parameters.  Though I guess the same could be done there with a single template implementation and aliases.

>>>> The compiler can inspect the code however, and a global const is as good as an invariant for optimization (as far as I know).  As for the rest, I think the majority of remaining cases aren't ones where 'invariant' would apply anyway: dynamic buffers whose contents are guaranteed not to change either in word or by design, etc.
>>>
>>> But they do apply - that's the whole array optimization thing. You're not just going to have global arrays.
>>
>> Perhaps I misunderstood the "must be known at compile-time" clause.  Can 'invariant' apply to dynamic arrays that will remain unchanged once initialized?  In my work I use almost no static data--it's all generated on the fly or loaded from some data source.  Will 'invariant' help to make my code more optimal?
> 
> Of course, that's the whole point of invariant. The 'invariant' keyword is being used for two things, compile-time values, and invariant data. You obviously can't do what you mention with compile-time values, but you can with invariant data (which is created at runtime). (or have I misunderstood you, and you already knew that?)

I didn't know that, and that was the source of my confusion.  I had thought that 'invariant' only applied to data which was initialized at compile-time.  That it can apply to run-time initialized data makes a world of difference.


Sean
June 24, 2007
Derek Parnell wrote:
> On Sat, 23 Jun 2007 08:32:36 -0700, Sean Kelly wrote:
> 
>> Will 'invariant' help to make my code more optimal?
> 
> Yeah ... what he said.
> 
> I'm with Sean on these points. There seems to be a false dichotomy being
> peddled here; that optimal run-time performance is mutually exclusive with
> source code that is cheap to write and maintain.

I am coming to feel that Walter's argument may just have been poorly presented, and that this is actually not the case.  But I'll admit some lingering trepidation about the apparent complexity of the design.

> D is so close to given us both that I constantly scream at the ugly warts
> that is being instilled into this wonderful language.

Same here.

> I agree that the concepts behind 'const' and 'invariant' represent two
> different and valid concepts that need to be catered for. The problem is in
> their proposed implementation. The keywords chosen are a hinderence to D
> source maintenance because they both appear to mean either of these two
> concepts. Sure, they will be learned and distingushed in one's mind over
> time, I've no doubt of that, but that is the problem in itself. Instead,
> why not use different key words that actually reflect the differences in
> the two concepts.

Exactly.  I think a lot of the confusion (now and in the future) may stem from the semantic overlap of these two terms.  The best alternative I've been able to come up with, though, is 'view' in place of 'const' and 'const' in place of 'invariant'.  And I know this suggestion has been shot down in the past.  'final' seems to fit the use to which it has been put, however.

> A second issue I have is that by forcing 'const' to be explicitly coded in
> function parameter lists, you are reducing the ability of the compiler to
> help detect bugs.

Isn't this necessary though?  Say the function declaration is available to the compiler but the implementation is not.  The compiler needs to know what kind of data can legally be passed as parameters.


Sean
June 24, 2007
Walter Bright wrote:
> Bill Baxter wrote:
>> Walter Bright wrote:
>>> Optimization often makes the difference between a successful project and a failure. C++ has failed to supplant FORTRAN, because although in every respect but one C++ is better, that one - optimization of arrays - matters a whole lot. It drives people using C++ to use inline assembler. They spend a lot of time on the issue. Various proposals to fix it, like 'noalias' and 'restrict', consume vast amounts of programmer time. And time is money.
>>
>> FORTRAN is also helped by having a fairly standardized ABI that can be called easily from lots of languages, which C++ lacks.  But C has that, and it has also failed to supplant FORTRAN for numeric code.  But I think Sean's right.  A lot of that is just that the language supports things like actual multi-dimensional arrays (by 'actual' I mean contiguous memory rather than pointers to pointers),
> 
> C has them too:
>     int array[3][5];
> is not an array of pointers to arrays.
> 
>> and mathematical operations on them right out of the box.
> 
> No, FORTRAN does not have array operations out of the box. It has no more mathematical operations than C does (in fact, it has fewer).

Hmm, maybe I'm thinking of Fortran 90 then.
This doc seems to be saying that F90 has array ops
http://www.ibiblio.org/pub/languages/fortran/ch1-2.html
"Fortran 90 supports an array notation that allows operations on array sections, and using vector indices."
And from that page, Fortran has an efficient built-in exponentiation operator, which sounds to me like one more operation than C has.  But I guess C has all the += type things, which I don't think Fortran has.  So I guess you could argue that C has more than F77 at least.

Anyway, that page there pretty much sums up all the arguments for why to use Fortran for numerical computing, straight from a Fortran guy's mouth, so I can't really add much more than that.

>> I guess what I'd like to say in summary is that I'm skeptical about the claim that optimization "often" makes the difference between success and failure.  "occasionally" I could believe.  Ill-advised premature optimization has probably led to the demise of many more a project than actual optimization problems in the end product.  We'll all gladly take a free 20% speed improvement if the compiler can give it to us, but I don't believe there are that many projects that will fail simply for lack of that 20%.
> 
> When you're paying by the minute for supercomputer time, 20% is a big deal.
> 
> When you're predicting the weather, a 20% slowdown means you're producing history rather than predictions.
> 
> If Google could get 20% more speed out of their servers, they could cut the size of their server farm by 20%. That's hundreds of millions of dollars.
> 
> When you're writing a game, numerics performance is what makes your game's graphics better than the competition.
> 
> When you're writing code for embedded systems, faster code means you might be able to use a slower, cheaper processor, which can translate into millions of dollars in cost savings when you're shipping millions of units.
> 
> I don't want D to be fundamentally locked out of these potential markets. If D compilers can produce fundamentally better code than C++, that's a big selling point for D into companies like Google. And when they use it for their critical server farm apps, they'll naturally tend to use it for much more.

That's all true but at the same time Java on embedded systems is pretty popular from what I understand, and Google is a big user of Python.

I guess we're just quibbling over the definition of the "often" in your statement "Optimization often makes the difference between a successful project and a failure."

Certainly it makes a difference sometimes.  And those are the times you're going to want to use a compiled language like D.  So I definitely agree that it makes sense for D to be second to none in generating optimized code and applaud your efforts in making the language amenable to such.

--bb
June 24, 2007
Don Clugston wrote:
> Walter Bright wrote:

>> You can't do that with C/C++ because arrays can be aliased. I have a stack of papers 6" deep in the basement on trying to make C more suitable for numerics, and it's mostly about, you guessed it, fixing the alias problem. They failed.
> 
> How much of this will actually be solved by invariant?
> It seems to me that typically, arrays are built up element-by-element, even if they never change again. I guess in D2.0, such code would initialize a temporary array, and finally idup it?
> 
> The aliasing problem will be far from gone, though. Consider an in-place operation on a matrix. Frequently you modify one only row at a time, based on the remaining rows. I think you'd have to cast(invariant) those other rows, to avoid aliasing.

Thanks for asking this.  It's been eating at me too.  From what I understand of Fortran code, you declare an array of a given size, set its values however you like, then pass it to a function.  But if we make an invariant D array we can't set its values after initialization.  So it doesn't seem very useful.  Or is the use pattern going to be, as you say, Don, casting to invariant every time you need to call fast_math_array_function()?  If that's the case I suspect it won't take long before this becomes an idiom:

   /* x += y array-style */
   add_accum(double[] x, const double[] y) {
      _add_accum_impl(cast(invariant)x,cast(invariant)y);
   }

Is that really what we want?
That code can't even be right though, because x is *supposed* to get modified there. So how do you denote lack of aliasing on something like that using invariant?  In this respect C99's 'restrict' seems to be a lot more understandable.  My naive understanding of it being that you just slap it on any argument that you want to tell the compiler it can assume to be non-aliased.

--bb
June 24, 2007
Sean Kelly wrote:
> Derek Parnell wrote:

>> A second issue I have is that by forcing 'const' to be explicitly coded in
>> function parameter lists, you are reducing the ability of the compiler to
>> help detect bugs.
> 
> Isn't this necessary though?  Say the function declaration is available to the compiler but the implementation is not.  The compiler needs to know what kind of data can legally be passed as parameters.

I took that to mean he wanted to make const the default.

I too am disappointed that the only rebuttal from Walter on const by default has been "some C++ guys I talked to thought it was weird".

--bb
June 24, 2007
Bill Baxter wrote:
> Sean Kelly wrote:
>> Derek Parnell wrote:
> 
>>> A second issue I have is that by forcing 'const' to be explicitly coded in
>>> function parameter lists, you are reducing the ability of the compiler to
>>> help detect bugs.
>>
>> Isn't this necessary though?  Say the function declaration is available to the compiler but the implementation is not.  The compiler needs to know what kind of data can legally be passed as parameters.
> 
> I took that to mean he wanted to make const the default.
> 
> I too am disappointed that the only rebuttal from Walter on const by default has been "some C++ guys I talked to thought it was weird".

Same here.  It's an elegant concept and I'd really like to give it a try.  I think only experience could tell whether it's a practical solution.


Sean
June 24, 2007
Sean Kelly wrote:
> Bill Baxter wrote:
>> Sean Kelly wrote:
>>> Derek Parnell wrote:
>>
>>>> A second issue I have is that by forcing 'const' to be explicitly coded in
>>>> function parameter lists, you are reducing the ability of the compiler to
>>>> help detect bugs.
>>>
>>> Isn't this necessary though?  Say the function declaration is available to the compiler but the implementation is not.  The compiler needs to know what kind of data can legally be passed as parameters.
>>
>> I took that to mean he wanted to make const the default.
>>
>> I too am disappointed that the only rebuttal from Walter on const by default has been "some C++ guys I talked to thought it was weird".
> 
> Same here.  It's an elegant concept and I'd really like to give it a try.  I think only experience could tell whether it's a practical solution.

Oh I forgot -- he did give two reasons, actually:
1) some c++ guys he talked to think it's weird.
2) didn't want to have to have a mutable keyword.
   (And in some other message later he said something about not wanting 'mutable' in D because it left a bad taste in the mouth of some C++ guys.)

I still think anti-const keywords would be useful even *without* const by default.  So #2 seems kind of odd to me.  Seems to me it would be very handy to be able to say something like:
    mutable T foo(T)(T input) {
       mutable T mungeable;
       // munge the mungeable based in the input
       return mungeable
    }
Sure there's other ways to accomplish that, but that seems like a particularly clear way to express "same type as T but not const".
You could also make templates to strip it like they do in C++.  then you could have

    Mutable!(T) foo(T)(T input) {
    }

Either way I don't see any real insurmountable or even troublesome issue there with #2.

--bb