July 09, 2012
On Mon, Jul 09, 2012 at 08:07:22PM +0200, Timon Gehr wrote:
> On 07/09/2012 07:49 PM, Andrei Alexandrescu wrote:
> >On 7/9/12 12:34 PM, David Piepgrass wrote:
> >>I guess D does not have 'mutable' (like C++) to override const on
> >>methods?
> >
> >It doesn't, which makes life difficult for certain idioms. On the upside, you can assume more than C++ does about immutable data.
> >
> >>Caching anything slow-to-compute is my typical use case, and I know a hashtable design where the getter will move whatever value at finds to the front of a hash collision chain.
> >
> >Yah, that won't be easy to implement. We have a couple of designs in mind for "mutable", but didn't get to it. Regarding advantages, think of this - if an immutable instance of your bring-to-front hashtable were used by multiple threads it would fail because it's "lying" about its being immutable. For now just don't use const for what ain't.
> >
> 
> This is very inconvenient if the root of the class hierarchy uses it.
[...]

I'm wondering if it makes any sense to have _also_ have non-const versions of things like toString, for objects that want to implement caching. So in contexts where const is not important, you can have caching, network access, whatever you want, but for core language stuff that needs to assume const, everything will still work (just a little slower).

I'm thinking of the case where some objects might be kept in ROM, say, in which case you can't cache within the class, even if you wanted to. But for other instances of the class that are outside ROM, you can be free to use the non-const, caching, network-accessing version of toString to your heart's content.

After all, we have inout for a reason; here's a case where we need to do the opposite of inout (have both a const and non-const version of a method).

Or am I just spouting nonsense again? ;-)


T

-- 
Help a man when he is in trouble and he will remember you when he is in trouble again.
July 09, 2012
On Monday, July 09, 2012 11:53:05 H. S. Teoh wrote:
> I'm wondering if it makes any sense to have _also_ have non-const versions of things like toString, for objects that want to implement caching. So in contexts where const is not important, you can have caching, network access, whatever you want, but for core language stuff that needs to assume const, everything will still work (just a little slower).

That works as long as the const version still works. As soon as you _need_ to mutate in order to do opEquals, opCmp, toString, or toHash (as can happen with lazy loading schemes), it doesn't work. Basic caching should work with that though.

- Jonathan M Davis
July 09, 2012
On Monday, July 09, 2012 10:01:25 Andrei Alexandrescu wrote:
> On 7/9/12 3:52 AM, Jonathan M Davis wrote:
> > On Sunday, July 08, 2012 23:37:29 Adam Wilson wrote:
> >> First I want to mention two people who really helped make this day happen.
> > 
> > Andrei is the one who was doing most of the work by reviewing and merging most of the pull requests which got merged.
> 
> Giving me credit for this is like giving credit the cable for electricity. I just let the great work of others flow.

It's a team effort, but the processing of pull requests has been a definite bottleneck. I'd say that for Phobos, 90+% of the time it's either you or me who merges them, so if either of us is slow about it and/or another Phobos dev is needed to review a particular request, then pull requests tend to languish. It's even worse for druntime, since a lot of the time, Sean needs to get involved (particularly since some of us feel a bit unqualified reviewing and merging some of the critical stuff in druntime), and he seems to be very, very busy (though with Martin Nowak recently added as a committer for druntime, the situation may improve). So, the fact that you took the time to review and merge so many pull requests had a big impact.

- Jonathan M Davis
July 09, 2012
On Mon, 09 Jul 2012 12:24:12 -0700, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Monday, July 09, 2012 10:01:25 Andrei Alexandrescu wrote:
>> On 7/9/12 3:52 AM, Jonathan M Davis wrote:
>> > On Sunday, July 08, 2012 23:37:29 Adam Wilson wrote:
>> >> First I want to mention two people who really helped make this day
>> >> happen.
>> >
>> > Andrei is the one who was doing most of the work by reviewing and  
>> merging
>> > most of the pull requests which got merged.
>>
>> Giving me credit for this is like giving credit the cable for
>> electricity. I just let the great work of others flow.
>
> It's a team effort, but the processing of pull requests has been a definite
> bottleneck. I'd say that for Phobos, 90+% of the time it's either you or me
> who merges them, so if either of us is slow about it and/or another Phobos dev
> is needed to review a particular request, then pull requests tend to languish.
> It's even worse for druntime, since a lot of the time, Sean needs to get
> involved (particularly since some of us feel a bit unqualified reviewing and
> merging some of the critical stuff in druntime), and he seems to be very, very
> busy (though with Martin Nowak recently added as a committer for druntime, the
> situation may improve). So, the fact that you took the time to review and
> merge so many pull requests had a big impact.
>
> - Jonathan M Davis

When I mentioned this post on IRC he specifically requested to be left out of it. So I did. However, I personally feel that his willingness to get in there and swing his +50 Hammer of Merging did in fact have a big impact on the successes of yesterday.

-- 
Adam Wilson
IRC: LightBender
Project Coordinator
The Horizon Project
http://www.thehorizonproject.org/
July 09, 2012
On Monday, July 09, 2012 12:28:32 Adam Wilson wrote:
> When I mentioned this post on IRC he specifically requested to be left out of it. So I did. However, I personally feel that his willingness to get in there and swing his +50 Hammer of Merging did in fact have a big impact on the successes of yesterday.

Ah. Okay. It just seemed really odd to me that you were singling people out and didn't say anything about him.

I've never used the D IRC channel, so I have no clue what goes on in there. I lose enough time just dealing with the newsgroup.

- Jonathan M Davis
July 09, 2012
On Monday, 9 July 2012 at 14:59:31 UTC, H. S. Teoh wrote:
> On Mon, Jul 09, 2012 at 01:44:24PM +0200, Timon Gehr wrote:
>> On 07/09/2012 08:37 AM, Adam Wilson wrote:
>> >Object is now const-correct throughout D. This has been a dream for
>> >many of you. Today it is a reality.
>> 
>> PITA. Forced const can severely harm a code base that wants to be
>> flexible -- it leaks implementation details and is infectuous.
> [...]
>
> Can you give an explicit example of code that is harmed by const
> correctness? IME, it rather helps code quality than harm it. Besides,
> since everything converts to const, it doesn't harm as much code as one
> might imagine (most code will be unchanged except where it matters --
> which IMO is a good thing).
>
> But YMMV.
>
>
> T

This is like the third time I bring up this example around this topic, but forcing const harms wrappers of state-machine style interfaces, which many C libraries use.

Here's LuaObject.opEquals from LuaD:

	/**
	 * Compare this object to another with Lua's equality semantics.
	 * Also returns false if the two objects are in different Lua states.
	 */
	bool opEquals(T : LuaObject)(ref T o) @trusted
	{
		if(o.state != this.state)
			return false;

		push();
		o.push();
		scope(success) lua_pop(state, 2);

		return lua_equal(state, -1, -2);
	}

This works because LuaObject is currently a struct, but that's an irrelevant detail, it could just as well be a class in a different scenario.

This opEquals is only logically constant, not bitwise constant, hence it must not be const; similar to the caching scenario. Just trying to demonstrate that the issue is bigger than just caching - it's any logically constant comparison function.
July 10, 2012
On 10 July 2012 01:02, Timon Gehr <timon.gehr@gmx.ch> wrote:
> 1.
>
> Most code that gives amortized complexity guarantees, eg:
>
> interface Map(K, V){
>     V opIndex(K k) const;
>     // ...
> }
>
> class SplayTree(K, V) : Map!(K, V) {
>     // ???
> }
>
> 2.
>
> - hash table
> - opApply compacts the table if it is occupied too sparsely, in order
>   to speed up further iteration.
> - toString iterates over all key/value pairs by the means of opApply.
>
> Clearly, toString cannot be const in this setup.
>
> 3.
>
> Often, objects can cache derived properties to speed up the code. With 'const-correctness' in place, such an optimization is not transparent nor doable in a modular way.
>
>
>
>> IME, it rather helps code quality than harm it.
>
>
> I am not talking about code quality. I am talking about code maintainability, extensibility and performance.

Although I don't know what D's goals with const are, in C++, const-correctness is often considered from the perspective of outside the interface. A const member function guarantees that, from the point of view of an entity using the object, its state will not change. This does not guarantee that data stored in the object is not changing. This allows for things like storing cached values. Unfortunately, implementing this is more difficult than it might sound, e.g. in cases such as  #2 above, particularly if you also want the compiler checking that the const keyword can allow (which you should).

See here for more information: http://www.parashift.com/c++-faq-lite/mutable-data-members.html

Geoff
July 10, 2012
On 07/10/2012 01:57 AM, Geoffrey Biggs wrote:
> On 10 July 2012 01:02, Timon Gehr<timon.gehr@gmx.ch>  wrote:
>> ...
>> 2.
>>
>> - hash table
>> - opApply compacts the table if it is occupied too sparsely, in order
>>    to speed up further iteration.
>> - toString iterates over all key/value pairs by the means of opApply.
>>
>> Clearly, toString cannot be const in this setup.
>>
>> ...
>> I am not talking about code quality. I am talking about code
>> maintainability, extensibility and performance.
>
> Although I don't know what D's goals with const are, in C++,
> const-correctness is often considered from the perspective of outside
> the interface. A const member function guarantees that, from the point
> of view of an entity using the object, its state will not change. This
> does not guarantee that data stored in the object is not changing.
> This allows for things like storing cached values. Unfortunately,
> implementing this is more difficult than it might sound, e.g. in cases
> such as  #2 above, particularly if you also want the compiler checking
> that the const keyword can allow (which you should).
>
> See here for more information:
> http://www.parashift.com/c++-faq-lite/mutable-data-members.html
>
> Geoff

Exactly! I don't think that the term 'const correctness' actually
has a meaning in D. It is a C++ term.
July 10, 2012
David Piepgrass:

> This use case is pretty complex, so if I port this to D, I'd probably just cast away const/immutable where necessary.

You are not the first person that says similar things. So D docs need to stress more than casting away const/immutable in D is rather more dangerous than doing the same thing in C++.

Bye,
bearophile
July 10, 2012
On Tuesday, 10 July 2012 at 01:41:29 UTC, bearophile wrote:
> David Piepgrass:
>
>> This use case is pretty complex, so if I port this to D, I'd probably just cast away const/immutable where necessary.
>
> You are not the first person that says similar things. So D docs need to stress more than casting away const/immutable in D is rather more dangerous than doing the same thing in C++.

 Depends on what you are trying to do I suppose. The only mutation I would use is a new object (and cast away const to do a bulk copy which is otherwise annoying to do). If something is const(ant), it means you don't intend to change it. Perhaps this is a bad example:

 Let's say a class/struct is a book with Page protectors signifying 'const(ant)'. You promise to return the book to the library without making any changes; Although you promised you wouldn't make changes, you still take the Page protectors off and make make notes on the outer edges or make adjustments in the text, then return the book.

 Is this wise? This isn't C++. If something shouldn't change, then don't change it god damn it. If it needs to change it isn't const(ant) and shouldn't suggest it is. If the functions are const(ant) that you need to use, make non-const(ant) versions (or ensure the original(s) are unmodified) and/or disable the original ones (if you can/need, I think?).

 Seriously, it's not that hard a concept. I guess if something doesn't port well from C++ then redesign it. Some things done in C++ are hacks due to the language's limitations and faults.

 I hope I'm not rambling too much.