May 14, 2012
On Monday, May 14, 2012 21:18:42 deadalnix wrote:
> This whole thing is overinflated. This isn't a problem. I'm pretty sure that most code that will broke was actually already a bad idea in the first place.

I'm fine with it, but there are people who complain quite bitterly about it (generally game programmers, I think - people with pretty insane restrictions on their programs due to very strict performance requirements).

- Jonathan M Davis
May 14, 2012
On Mon, May 14, 2012 at 11:55:15PM +0400, Dmitry Olshansky wrote:
> On 14.05.2012 23:26, Steven Schveighoffer wrote:
[...]
> >Oh, and also, we should fix that problem (that writef allocates). However, I think we need DIP9 in order to do that. http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP9
> >
> 
> DIP9 for the win!
> I tried to revive at least *some* interest in it for a long time.
[...]

+1.

I like this proposal. I have never liked the idea of toString() ever since Java introduced it.  Besides memory usage issues, toString() also binds you to the string type for no good reason: what if you wanted to store the result into a database file? Why waste resources on an intermediate representation if it can be written straight to its final destination?

I'd even argue that DIP9 is an excellent example of:

http://en.wikipedia.org/wiki/Dependency_inversion_principle

We don't know what representation the caller ultimately wants (string in memory, file on disk, network socket, etc.), so why impose an essentially arbitrary concrete representation type? Let the delegate decide what to do with the data.


T

-- 
Just because you survived after you did it, doesn't mean it wasn't stupid!
May 14, 2012
On Monday, 14 May 2012 at 19:24:15 UTC, Steven Schveighoffer wrote:
> I have never seen this suggested before.  I would guess that it might be considered a bug, since you are accessing the outer instance via a pointer contained in the inner instance.
>
> But I like the approach (even if it is a bug)!

 I was thinking something along these lines last night, although I couldn't put it quite together, it did end up using alias this.


 I forget but someone commented on possibly using a flag that would let you write to a variable for the first time, and break if you tried to read from it. A thought that went through my head would indeed need a little thought, but I couldn't see an easy way to do it outside of a new keyword. What if .init (or null) was your flag effectively? Let's assume allowinit (or something better) to be the keyword. Then...

struct S {
  allowinit uint hash;

  uint toHash() const {
    if (hash == uint.init) { //read always allowed safely within struct
        hash = 1;
    }

    return hash;
  }

  void throwtest() {
    hash = 2; //might not throw
  }
}

func(){
 const S s, z;

// writeln(s.hash);   //throw!

 //throwtest();       //would not throw here
 writeln(z.toHash()); //fine
 writeln(z.toHash()); //yep still fine
 writeln(z.hash);   //allowed? technically yes...

 throwtest();       //throw!
}

 Course these types may cause more problems if outside code had to do extra checks, so making allowinit forced to be private would remove that issue leaving it only to within the struct, making it good for caching results as you could only set it once.

 But that only works with const data, immutable being locked in memory it wouldn't do the job. So the only way to get around that is to allow a constructor that sets it during construction.

//as above
struct S {
  this(uint h) {
    hash = h;
  }
}

func(){
  immutable S i; //compile error! Immutable cannot have allowinit with default constructor!
  immutable S i2 = S(10); //fine
  immutable S i2 = S(uint.init); //error! allowinit cannot be assigned to .init value for immutable!
}


May 14, 2012
On 05/14/2012 09:18 PM, deadalnix wrote:
> Le 14/05/2012 04:47, Jonathan M Davis a écrit :
>> They can be in almost all cases. The problem is the folks who want to
>> have
>> caching and/or lazy initiailization in their classes/structs. You
>> can't cache
>> the result of any of those functions (toHash being the main target for
>> it) if
>> they're const and pure except in overloads which _aren't_ const,
>> making those
>> functions more expensive in comparison to what they could be if they
>> weren't
>> required to be const. And lazy initialization becomes almost impossible,
>> because if the member variables needed in those functions haven't been
>> initialized yet when they're called, then you _can't_ initialize them. If
>> getting the value that it _would_ be without actually initializing the
>> member
>> variable works, then you can do that if it hasn't been initialized,
>> but if you
>> can't do that (e.g. the variable _must_ be set only once), then you're
>> screwed. And regardless of whether you can make it work with const, it
>> _will_
>> be less efficient.
>>
>
> Lazy initialization is more a problem than a solution when it comes to
> multithreading.

How to solve the problem of representation of infinite data structures otherwise?

> And I'm afraid it is the future.
>

Sharing mutable data frivolously is likely not the future. I guess that usually every thread will have its own cache.

> BTW, nothing prevent to define toString an non const and another as
> const. The const one cannot cache the result, but certainly can read it.
> And every method that is aware of the non const version will use it.
>
> This whole thing is overinflated. This isn't a problem. I'm pretty sure
> that most code that will broke was actually already a bad idea in the
> first place.

That is a rather optimistic assumption. And even if it is true for 'most' code, that is not enough imho.
May 14, 2012
On 5/14/2012 10:08 AM, Tove wrote:
> but c++ has the 'mutable' keyword as an easy escape route...

The existence of that capability means that 'const' in C++ cannot be meaningfully reasoned about.
May 14, 2012
On Monday, 14 May 2012 at 12:22:30 UTC, Steven Schveighoffer
wrote:
> On Mon, 14 May 2012 02:35:16 -0400, Jakob Ovrum <jakobovrum@gmail.com> wrote:
>>
>> How about logically constant opEquals, toString etc? Currently, this is perfectly possible by just *not using const*. Logical constancy goes beyond memoization.
>
> This means you cannot compare two const objects.

Yes, but using const for these objects makes no sense because
they all require temporary mutation (the Lua stack) to do
anything meaningful. This includes opEquals and toString. Thus
the option should be there not to use const.

> The issue is, non-const opEquals makes sense on some objects, and const opEquals makes sense on others.  However, you must make them all come together in Object.opEquals.
>
> I think we already have the hooks to properly compare objects without requiring Object.opEquals.
>
> Right now, when two objects are compared, the compiler calls object.opEquals (that's little o for object, meaning the module function *not* the class method).
>
> So why can't object.opEquals be a template that decides whether to use Object.opEquals (which IMO *must be* const) or a derived version?  I don't think it's that much of a stretch (not sure if we need a compiler fix for this).
>
> -Steve

Right, I think this is the way to go. We have to accommodate both
kind of object.

May 15, 2012
On Monday, 14 May 2012 at 18:52:06 UTC, deadalnix wrote:
> The only reason I'd see a toSting function as non pure or non const is memoize. It can be tackled with lib support in phobos.
>
> What are other uses cases ?

Did you miss my post?

http://forum.dlang.org/post/azevkvzkhhfnpmtzgnvp@forum.dlang.org

May 15, 2012
On 5/14/2012 12:47 AM, Chris Cain wrote:
> And all this together culminates into a much greater ability to _reason about
> code_.

Exactly. And ditto for the rest of your post - it's spot on.

Being able to reason about code is *intensely* important. All those decorations - const, pure, nothrow, out - serve to help that out.
May 15, 2012
On 5/14/2012 1:03 AM, Mehrdad wrote:
> On Monday, 14 May 2012 at 06:27:15 UTC, Walter Bright wrote:
>> #3 Improves self-documentation of code - it's more understandable and less
>> susceptible to breakage during maintenance.
>
> #3 is also valid for C++, so I wasn't exactly considering that.

No, it isn't.

1. C++ legally allows changing const values.

2. const only applies to the top level (i.e. head const). So if you have anything more than a simple value type, it literally means *nothing*.

>
>> #4 Improves encapsulation
>
> o.O How does it improve encapsulation?

By guaranteeing that the method call is a reader, not a mutator.


D is a very deliberate step away from correctness by convention and towards correctness with mechanical verification.

May 15, 2012
Walter Bright:

> Being able to reason about code is *intensely* important. All those decorations - const, pure, nothrow, out - serve to help that out.

Bertrand Meyer (Eiffel author) is now working a lot on this, as
you see from many of the last posts on his blog
(http://bertrandmeyer.com/ ). The "Modern Eiffel" language is
being designed right to allow more reasoning about code. This
seems a small trend in new languages, but I can't predict how
much important it will become in ten years.

Bye,
bearophile