January 21, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Walter Bright wrote:
>> My objections to the C++ const are:
>>
>> 1) there are *legal* ways to subvert it, meaning it is useless as a semantic aid and useless to the optimizer/code generator
>> 2) it confuses a type modifier with a storage class (exhibiting muddled special case behaviors)
> 
> Let me point out that D's current handling of the storage classes is broken. D defines the 'inout' and 'out' storage classes which are undetectable for templates and break any template code that needs to deal with them. (Why in the world was 'out' ever needed? Probably the "working with IDL" assumption should be revisited.) Then, to add insult to injury, D defines the 'lazy' storage class that changes the access syntax (something that a storage class is not supposed to do), does not allow assignment from the same type (although it should), and again can't work with any template code.

"in", "out", "inout" and "lazy" aren't storage classes.
http://www.digitalmars.com/d/declaration.html (in the big syntax block at the top):
-----
StorageClass:
        abstract
        auto
        const
        deprecated
        extern
        final
        override
        scope
        static
        synchronized
-----
and later:
-----
InOut:
        in
        out
        inout
        lazy
-----

They're more like parameter passing conventions:
* You can only use one per parameter
* You can't declare a global variable to be 'lazy' ;).
* You can't declare a parameter to be 'abstract', 'auto', 'const', ...

They're pretty distinct concepts. They just look similar because they're used in such similar positions (typically before a type + name), but in two different contexts.

I do agree that it's weird the access syntax is changed by a parameter passing convention.




By the way, looking at that part of the spec I noticed something weird. I can't find the path that would allow "(int x)" to be a valid parameter list. /Parameter/ has 4 cases. In this case "Declarator" would be the obvious clause (no '=', no in/out). But /Declarator/ doesn't seem to allow 'int' at the start (or any basic type for that matter). It just allows:
* type suffixes (*, [], [ /Expression/ ], delegate /Parameters/, function /Parameters),
* /Identifier/ (which doesn't include basic types as they're keywords),
* parenthesized /Declarator/
* /Identifier/ /DeclaratorSuffixes/ (see /Identifier/ case)
* parenthesized /Declarator/ followed by /DeclaratorSuffixes/ (see case before previous)

This seems to be an oversight; in /Decl/ the type (/BasicType/) is put before every instance of /Declarators/. Perhaps they were lifted out when auto declarations were added but the /Declarator/ in the parameter list syntax was overlooked?
January 21, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
>> Andrei Alexandrescu (See Website for Email) wrote:
>>> The reflection mechanism would have to provide the information whether
>>> or not a given member function changes the object.
>>>
>>> The only drawback that I can think right now is that the compiler can't
>>> exploit this kind of constness with ease to generate better code; it's a
>>> "user-space" implementation with semantics that are hard to figure out
>>> at the compiler level.
>>>
>>> A minor drawback is that Const!(Foo) must be implicitly constructible
>>> from a Foo, but another in-design language feature (opImplicitCast) will
>>> take care of that.
>>
>> Correct me if I'm wrong, but I think none of this stuff will work for methods that are only declared instead of defined as well; 'const', implemented like this, wouldn't work for "header modules"...
> 
> That is correct. Interface functions, nonfinal methods, and declared-only functions must be annotated manually. The same holds for things like "pure". Hopefully they are only a fraction of the entire const use, such that the burden of the programmer is reduced.

If explicit annotation is possible then this could work for this case. Especially if "dmd -H' automatically added these annotations where appropriate.



You didn't respond to my paragraph on classes though:

Frits van Bommel wrote:
> I also don't see a way this can work for classes (in general). There's
> no way to limit a non-final method to non-mutating operations that I'm
> aware of, so it could easily be circumvented by subclassing. Even though
> that would only allow direct access to non-private fields, mutating base
> class methods could still be called for the rest (if available). So then
> the only way to get a const version of a class would be if the class
> doesn't allow mutations anyway (like java's String). Which leaves us
> right back where we started :(.
>
> And I don't think a 'const' implementation should work for structs and
> not for classes...

January 21, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> I'm positive that lazy is the epitome of bad language design and should go away. The article:
> 
> http://www.digitalmars.com/d/lazy-evaluation.html
> 
> proudly acknowledges the post:
> 
> http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=41633 
> 
> 
> which doesn't make any sense of anything,

Well, thanks for the attack, but it was an attempt to suggest a fix, as the introduction of lazy evaluation broke existing code in a non-trivial way.


> confuses lazy/delegates with expression templates,

For a good reason. If I remember correctly, Walter compared lazy evaluation to expression templates in his earlier posts.


> and fails to provide both a solid argument for 'lazy'

The arguments popped up in various discussions on the NG and #d on IRC.


> and the shade of a valid design for it.

It was a suggestion for one possible way to avoid breaking existing code - not a final and complete proposal. I was hoping for a discussion to follow.


> - templates are powerless with lazy, as they are with any other storage class; they are doubly powerless with lazy because they now need to deal with the modified access syntax.

Actually, inout/out can be detected by templates and std.bind does it. Still, inout cannot be distinguished from out.


> I believe that populism in language design is not good.

Listening to ideas and opinions from language users is a bad idea ? Taking my post as an example, it was merely a compromise between the screams of other D users and Walter's opinion. Had Walter ignored it, the net result would be more confusion and irritation, along with a strange rule of implicitly converting lazy expressions to delegates.


This said, I don't think that the way lazy expressions are currently implemented is even close to being optimal. out/inout could be changed too, as out/inout params can be detected, but one cannot realistically instantiate a function template with mixed in/out/inout params.


--
Tomasz Stachowiak
January 21, 2007
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@erdani.org> wrote in message news:45B3AB3F.5040707@erdani.org...
> Me too. I actually thought lazy is a storage class. It sure has the syntax of one in definition. It changes the use syntax (requires parens). And if I look at
>
> http://www.digitalmars.com/d/lazy-evaluation.html
>
> I see that lazy *is* a storage class.
>
> My original suggestion was to simply convert expressions to delegates automatically. That setup has its own problems, but I think it's much easier to deal with them than it is with lazy.
>
> A template can't detect lazy properly. It's unclear what it means to assign to a lazy parameter. Lazy is a storage class that changes the access syntax. I believe lazy is ill-designed. Walter should have stood the pressure and refuse to implement it without a clear definition.

I'm not sure how we got from 'const' to 'lazy' :) but let me just say that I think there's a lot of potential for lazy evaluation and I was very exited when Walter added the implicit conversion from expressions to delegates. I'm not sure what the problem with the keyword "lazy" is though (other than maybe its grammar). At the moment, I think of the keyword "lazy" as a shorter way to declare a delegate. A type saver, much like "length", if you will : D

Seriously though, I remember the last time I was excited about something similar. It was in the computer architecture class at the university and we were presented some NEC data flow processor. It was a CPU without an instruction pointer. Just packages of data with code attached. It was quite eliberating to see a totally different way of doing things. I think delegates/lazy-evaluation are a big step towards this kind of flow-based programming.

http://en.wikipedia.org/wiki/Flow-based_programming

L.


January 21, 2007
Frits van Bommel wrote:
> By the way, looking at that part of the spec I noticed something weird. I can't find the path that would allow "(int x)" to be a valid parameter list. /Parameter/ has 4 cases. In this case "Declarator" would be the obvious clause (no '=', no in/out). But /Declarator/ doesn't seem to allow 'int' at the start (or any basic type for that matter). It just allows:
> * type suffixes (*, [], [ /Expression/ ], delegate /Parameters/, function /Parameters),
> * /Identifier/ (which doesn't include basic types as they're keywords),
> * parenthesized /Declarator/
> * /Identifier/ /DeclaratorSuffixes/ (see /Identifier/ case)
> * parenthesized /Declarator/ followed by /DeclaratorSuffixes/ (see case before previous)
> 
> This seems to be an oversight; in /Decl/ the type (/BasicType/) is put before every instance of /Declarators/. Perhaps they were lifted out when auto declarations were added but the /Declarator/ in the parameter list syntax was overlooked?

I posted something a little while ago on d.D.bugs regarding the spec's grammar missing some things:

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.bugs&article_id=9962

-- 
Kirk McDonald
Pyd: Wrapping Python with D
http://pyd.dsource.org
January 22, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Dave wrote:
> 
> It is then possible they were wrong, or that they didn't come with a reasonable design. Speaking of which (famous last words to come), I don't want to sound harsh, but if there is one thing that's worse than language design by committee, that's got to be language design by community. Having too many cooks in the kitchen dilutes vision, which is probably the single most important thing in a language design. 

I couldn't agree more on this point.  I'm glad we have someone like Walter at the helm with a clear vision and an end goal.  I've been on a few design by committee projects and you can never get everyone to agree.  Projects would get to a point and then someone would who didn't like one direction would lose enthusiasm and then we were back to square one.

Someone needs to say, this doesn't fit into my overall picture and this is the way we should go forth.  Projects work best when there is a clear direction.

Having said that, I've been in groups where everyone was assigned a particular piece of the puzzle to be the lead on.  That seemed to work well.

> The few
> places where Walter made populist decisions are eminently visible in the language design (ah, "length", gotta love that one), and many feature requests that have been aired on this newsgroup are in dire need of design.


Here I don't agree, Walter (as much as we would like to believe) doesn't have the experience of the entire community collective.   He is wise to listen to others point of view.   He is even more wise to be willing to change his point of view, if a good enough argument can be put forth.

It's a very diplomatic way of doing things.

-Joel
January 22, 2007
Andrei Alexandrescu (See Website For Email) wrote:

> A template can't detect lazy properly. It's unclear what it means to assign to a lazy parameter. Lazy is a storage class that changes the access syntax. I believe lazy is ill-designed. Walter should have stood the pressure and refuse to implement it without a clear definition.

Well, the pressure, if any, was from you, the way I recall it.  There wasn't any kind of community upswell around that one.  The way I remember it was that 'lazy' just suddenly appeared out of the blue in D 0.165 (http://www.digitalmars.com/d/changelog.html#new0165 -- the 'expressions to delegates' bit), with Walter saying essentially "this is going to change the game, trust me! Andrei convinced me!"

But maybe I'm remembering it wrong.

Either way, pressure is pressure, and perhaps Walter should have withstood it regardless of where it was coming from... I just don't think you can pin any ill results in this case on "the community".

Just trying to set the record straight here. :-)

--bb
January 22, 2007
James Dennett wrote:
> Walter Bright wrote:
>> Bill Baxter wrote:
>>> The question is how can we write functions in D that take big structs
>>> as parameters in such a way that it is:
>>> A) efficient and
>>> B) guaranteed not to change the caller's value
>>>
>>> In C++ the answer is const LargeStruct&.
>> C++ doesn't *guarantee* it won't change. There are at least two legal
>> ways to do it.
> 
> This is an oft-repeated point, but it also misses the users'
> perspective.  It's important from an implementors perspective
> that this use of const as a type modifier doesn't provide the
> compiler with a guarantee of immutability.  Given sensible
> users, that doesn't generally matter to programmers writing
> code.  const documents an interface; it doesn't enforce it,
> though

Exactly.  The main reason I want to be able to have something like a const inout is because I want the compiler to let _me_ know when I'm writing some function if I accidentally modify some value that I promised in my interface that I wouldn't modify.

It doesn't bother me that the constness can be subverted by a cast.  In fact I'd *like* to be able to choose to modify some private bit of state in an object if necessary (e.g. private mutable members used for caching or somesuch).  D is a down-to-the-metal systems programming language, after all, not a nanny language.  In fact, I really don't see much practical use for a totally watertight, totally irrevocable const. (Unless it maybe opens the door for some sweet optimizations.  But I'd argue that should be a separate thing from this const that's more of a promise about the interface.)

That said, I'm also certainly not in love with how const works in C++. At the end of the day, all I really want is an efficient way to pass big structs without suggesting in the interface that they'll be modified. But that leads naturally to const references, and then that basically leads to const everywhere, just like C++, since you can't pass any const parameter to another function that isn't also const.  :-(

--bb
January 22, 2007
Bill Baxter wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
> 
>> A template can't detect lazy properly. It's unclear what it means to assign to a lazy parameter. Lazy is a storage class that changes the access syntax. I believe lazy is ill-designed. Walter should have stood the pressure and refuse to implement it without a clear definition.
> 
> Well, the pressure, if any, was from you, the way I recall it.  There wasn't any kind of community upswell around that one.  The way I remember it was that 'lazy' just suddenly appeared out of the blue in D 0.165 (http://www.digitalmars.com/d/changelog.html#new0165 -- the 'expressions to delegates' bit), with Walter saying essentially "this is going to change the game, trust me! Andrei convinced me!"
> 
> But maybe I'm remembering it wrong.
> 
> Either way, pressure is pressure, and perhaps Walter should have withstood it regardless of where it was coming from... I just don't think you can pin any ill results in this case on "the community".
> 
> Just trying to set the record straight here. :-)

The feature I suggested was conversion from expression to delegate, which has a couple of problems, but nothing earth-shattering. Then somehow lazy materialized as a storage class out of the blue, but with the delegate syntax upon use, which is not a horse nor a donkey.

Walter and I have worked carefully through inout, lazy, and const today and managed to figure a semantics that makes sense for all storage classes and combinations thereof. (The () use syntax of lazy will go away.)


Andrei
January 22, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Bill Baxter wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>
>>> A template can't detect lazy properly. It's unclear what it means to assign to a lazy parameter. Lazy is a storage class that changes the access syntax. I believe lazy is ill-designed. Walter should have stood the pressure and refuse to implement it without a clear definition.
>>
>> Well, the pressure, if any, was from you, the way I recall it.  There wasn't any kind of community upswell around that one.  The way I remember it was that 'lazy' just suddenly appeared out of the blue in D 0.165 (http://www.digitalmars.com/d/changelog.html#new0165 -- the 'expressions to delegates' bit), with Walter saying essentially "this is going to change the game, trust me! Andrei convinced me!"
>>
>> But maybe I'm remembering it wrong.
>>
>> Either way, pressure is pressure, and perhaps Walter should have withstood it regardless of where it was coming from... I just don't think you can pin any ill results in this case on "the community".
>>
>> Just trying to set the record straight here. :-)
> 
> The feature I suggested was conversion from expression to delegate, which has a couple of problems, but nothing earth-shattering. Then somehow lazy materialized as a storage class out of the blue, but with the delegate syntax upon use, which is not a horse nor a donkey.
> 
> Walter and I have worked carefully through inout, lazy, and const today and managed to figure a semantics that makes sense for all storage classes and combinations thereof. (The () use syntax of lazy will go away.)
> 
> 
> Andrei

Great.  Sounds promising.  Looking forward to hearing the details.

--bb