August 09, 2010
On Mon, 09 Aug 2010 14:39:58 -0400, Lutger <lutger.blijdestijn@gmail.com> wrote:

> bearophile wrote:
>
>> Mafi:
>>> I think, that isn't a good idea.
>>
>> I agree, that idea doesn't work well.
>>
>> Bye,
>> bearophile
>
> I think it still is a good idea to forbid this in safe mode. Perhaps in trusted
> too.

Note, this isn't any less safe than defining whatever you want for a C function:

extern(C) int strlen(int x);

C has no mangling, so there is no storage of parameter types in the symbol.  You can call any C function with whatever parameters you want to define for them.  Making some set of parameters illegal because in some cases it might not be true where you don't prevent it in others because you can't prove it, is just simply useless.

-Steve
August 09, 2010
Steven Schveighoffer wrote:

> On Mon, 09 Aug 2010 14:39:58 -0400, Lutger <lutger.blijdestijn@gmail.com> wrote:
> 
>> bearophile wrote:
>>
>>> Mafi:
>>>> I think, that isn't a good idea.
>>>
>>> I agree, that idea doesn't work well.
>>>
>>> Bye,
>>> bearophile
>>
>> I think it still is a good idea to forbid this in safe mode. Perhaps in
>> trusted
>> too.
> 
> Note, this isn't any less safe than defining whatever you want for a C function:
> 
> extern(C) int strlen(int x);
> 
> C has no mangling, so there is no storage of parameter types in the symbol.  You can call any C function with whatever parameters you want to define for them.  Making some set of parameters illegal because in some cases it might not be true where you don't prevent it in others because you can't prove it, is just simply useless.
> 
> -Steve

Well you manually add typing, I think that is useful. But come to think of it, extern(C) functions should not be allowed in @safe code at all, only via @trusted and then the typing is useful. Perhaps this has been talked about, but I'm not sure how far @trusted can be allowed to go.

August 09, 2010
Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class.  But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign

You're right, I was thinking of immutable.

-- 
Simen
August 09, 2010
Simen kjaeraas <simen.kjaras@gmail.com> wrote:

> Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>
>> Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class.  But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign
>
> You're right, I was thinking of immutable.

This said, one of the reasons casting away const is undefined, is because
the underlying type may be immutable.

-- 
Simen
August 09, 2010
On Mon, 09 Aug 2010 15:49:12 -0400, Simen kjaeraas <simen.kjaras@gmail.com> wrote:

> Simen kjaeraas <simen.kjaras@gmail.com> wrote:
>
>> Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>>
>>> Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class.  But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign
>>
>> You're right, I was thinking of immutable.
>
> This said, one of the reasons casting away const is undefined, is because
> the underlying type may be immutable.

Right.  After reading all these replies, I think the way it looks to me is technically it's undefined to cast away const/immutable and write the data.  But, in certain circumstances, I think it will be possible to write portable code that works on all compilers that does this.

It's like a threading race condition.  If you simply allow unchecked access to a variable, it's undefined, you get races and can be using a partially written value, but slap a mutex around it, and the variable suddenly becomes well defined and behaves perfectly.  The compiler cannot guarantee this, nor detect it, but the programmer can determine based on analysis of all the code that it's safe.

-Steve
August 09, 2010
On Monday, August 09, 2010 07:13:31 Steven Schveighoffer wrote:
> Casting away const just to read the data is useless.  You can read const data without a cast.

That's not actually quite true. If all code were const-correct, then it would be, but much of D is not. For instance, toHash() is not const even though it should be. The result is that if you need to call it with a const object, you have to cast away the constness. No writing is going on there (unless the writer of the toHash() function in the derived class(es) screwed it up), but you can't call it with a const object. I've run into plenty of similar situations in C++ where whoever wrote the code didn't choose to use const at all, and it made making that code deal with const a royal pain if not totally unreasonable. Casting away constness in cases where you knew that no write was going to take place or just dropping the constness in in your code were the only two options.

If anything, my reaction would have been that the programmer has no business writing to anything that they cast away the constness of. Dealing with code which _could_ and _should_ be const but isn't is the only place that I've ever even considered casting away const.

- Jonathan M Davis
August 09, 2010
On Mon, 09 Aug 2010 17:15:41 -0400, Jonathan M Davis <jmdavisprog@gmail.com> wrote:

> On Monday, August 09, 2010 07:13:31 Steven Schveighoffer wrote:
>> Casting away const just to read the data is useless.  You can read const
>> data without a cast.
>
> That's not actually quite true. If all code were const-correct, then it would
> be, but much of D is not. For instance, toHash() is not const even though it
> should be. The result is that if you need to call it with a const object, you
> have to cast away the constness. No writing is going on there (unless the writer
> of the toHash() function in the derived class(es) screwed it up), but you can't
> call it with a const object.

Then the author failed to make it const, and it's a bug in the function definition.  "Casting away const if you don't write" is crap, and should be treated as suspiciously as code that writes to const data.

What if calculating the hash is expensive, and you know you don't have to recalculate it, you might cache it as a member of the class.  Believe me, if a programmer can do it, he will.  Documentation saying "don't do this!" isn't enough.

> I've run into plenty of similar situations in C++
> where whoever wrote the code didn't choose to use const at all, and it made
> making that code deal with const a royal pain if not totally unreasonable.

Casting away const in C++ and writing to the data I think is not undefined.  I believe that's one of Walter's gripes with C++ const.

-Steve
August 09, 2010
On Monday, August 09, 2010 15:01:28 Steven Schveighoffer wrote:
> Then the author failed to make it const, and it's a bug in the function definition.  "Casting away const if you don't write" is crap, and should be treated as suspiciously as code that writes to const data.

I totally agree that the author of the code screwed up. However, sometimes you have to deal with other people's screw ups. And unfortunately, in my experience, a _lot_ of programmers don't bother to write const-correct code, and it causes huge problems for those of us who do.

> What if calculating the hash is expensive, and you know you don't have to recalculate it, you might cache it as a member of the class.  Believe me, if a programmer can do it, he will.  Documentation saying "don't do this!" isn't enough.

That's why mutable would be highly desirable, but we don't have it so tough luck for us on that count, I suppose. As for documentation, if the function is const, then no documentation is necessary. They just can't do it (not without casting away constness and going into undefined territory anyway).

Personally, I'd say tough luck to the guy who wants to cache the hash by calculating it in toHash(). He can call some other function to cache it, or he could have a non-const version which caches it for cases where the object isn't const, or he could calculate it when something in the class changes (which naturally comes with its own set of pros and cons). From the perspective of logical constness, there is no reason why toHash() can't be const.

The one thing that stumps me is why associative arrays allow for const keys with toHash() not being const. If I were to try and write a hashtable implementation myself, I'd have to cast away the constness of the keys to be able to call toHash() on them, which would be _really_ annoying. Maybe that's what associative arrays are doing internally.

Personally, I tend to be of the opinion that if a function can be const, it should be const. There are always exceptions of course, but generally I think that functions should be const when possible. It allows for writing const- correct code much more easily (if not just outright makes it possible), and that can reduce the number of mutation bugs that programmers have to deal with.

- Jonathan M Davis
August 10, 2010
On Mon, 09 Aug 2010 19:35:38 -0400, Jonathan M Davis <jmdavisprog@gmail.com> wrote:

> On Monday, August 09, 2010 15:01:28 Steven Schveighoffer wrote:
>> Then the author failed to make it const, and it's a bug in the function
>> definition.  "Casting away const if you don't write" is crap, and should
>> be treated as suspiciously as code that writes to const data.
>
> I totally agree that the author of the code screwed up. However, sometimes you
> have to deal with other people's screw ups. And unfortunately, in my experience,
> a _lot_ of programmers don't bother to write const-correct code, and it causes
> huge problems for those of us who do.

Yes, but by using such code and casting away const you are:

1) opening up your application to potential undefined behavior if the code you are using changes in a way that actually *does* write to the object
2) opening up your *own* code to potential undefined behavior in case you accidentally forget that you casted away const.

Casting away const is bad unless you control all the elements involved, and I think you need to limit it to small pieces of code where you scrutinize every aspect of it.

I think creating a Mutable wrapper for a type can potentially be an asset if it's done correctly.

>> What if calculating the hash is expensive, and you know you don't have to
>> recalculate it, you might cache it as a member of the class.  Believe me,
>> if a programmer can do it, he will.  Documentation saying "don't do this!"
>> isn't enough.
>
> That's why mutable would be highly desirable, but we don't have it so tough luck
> for us on that count, I suppose. As for documentation, if the function is const,
> then no documentation is necessary. They just can't do it (not without casting
> away constness and going into undefined territory anyway).

As long as its encapsulated, I think we are ok.  Note that there are other parts of the instance that are always mutable, such as the monitor object.

> Personally, I'd say tough luck to the guy who wants to cache the hash by
> calculating it in toHash(). He can call some other function to cache it, or he
> could have a non-const version which caches it for cases where the object isn't
> const, or he could calculate it when something in the class changes (which
> naturally comes with its own set of pros and cons). From the perspective of
> logical constness, there is no reason why toHash() can't be const.

I've proven that logical const is doable without breaking const in a post a couple years ago.  It's just lacking the language support.  I also made an extremely complex proposal to allow specification of various levels of const but that was rejected on account of being too complex :)

But looking at things like Rebindable, I think we should be able to make a logical const type that allows what we need in a controlled manner.

> The one thing that stumps me is why associative arrays allow for const keys with
> toHash() not being const. If I were to try and write a hashtable implementation
> myself, I'd have to cast away the constness of the keys to be able to call
> toHash() on them, which would be _really_ annoying. Maybe that's what
> associative arrays are doing internally.

hehe, AA's are part of the runtime, so they manually must obey const rules.  Basically, they get a TypeInfo and a void * (which the compiler strips of any const or type) and have to do the right thing.  The TypeInfo's getHash() function takes a void *, so no const is obeyed, that's why it works.

> Personally, I tend to be of the opinion that if a function can be const, it
> should be const. There are always exceptions of course, but generally I think
> that functions should be const when possible. It allows for writing const-
> correct code much more easily (if not just outright makes it possible), and that
> can reduce the number of mutation bugs that programmers have to deal with.

I agree.

-Steve
1 2 3 4
Next ›   Last »