Accidentally killing immutable is too easy in D (Was: cast()x - a valid expression?)

Steven Schveighoffer schveiguy at yahoo.com
Thu Jun 2 15:13:22 PDT 2011


On Thu, 02 Jun 2011 17:52:41 -0400, Jonathan M Davis <jmdavisProg at gmx.com>  
wrote:

> On 2011-06-02 09:02, Bruno Medeiros wrote:
>> On 01/06/2011 22:12, Jonathan M Davis wrote:
>> >> It's nice in a way, but it's all based on the way cast handles
>> >> modifiers.
>> >>
>> >> > And I've always been a bit unconfortable with how that's handled  
>> (In
>> >> > fact, I was just thinking about this yesterday). Specifically, it
>> >> > seems extremely bad that it's so incredibly easy to accidentaly  
>> cast
>> >> > away things like const and immutable:
>> >> >
>> >> > For example, if I know I have an array of uint's, and I want to  
>> deal
>> >> > with the individual bytes, it's perfectly safe and sensible to cast
>> >> > it to a ubyte[] (a long as you factor in endianness, of course).  
>> So,
>> >> > you do "cast(ubyte[])myArray". But, OOPS!!: If myArray happened to
>> >> > be immutable, then merely trying to cast the type has inadvertantly
>> >> > cast-away immutable. Not good! Casting away const/immutable really,
>> >> > really should have to be explict.
>> >> >
>> >> > Of course, you can probably use some fancy helper templates to make
>> >> > sure you preserve all modifiers. But needing to do so is just  
>> asking
>> >> > for mistakes: it seems like a huge violation of "make the right way
>> >> > easy, and the wrong way hard".
>> >
>> > You really shouldn't be casting much anyway. It's the sort of feature
>> > where you're only supposed to use it when you know what you're doing
>> > when you use it. And if there's really any possibility that you're
>> > dealing with immutable, perhaps you should be casting to const rather
>> > than mutable. Personally, I find how C++ created multiple types of  
>> cast
>> > (include const_cast)_highly_ annoying and generally useless, and
>> > I'm_very_ glad that D didn't do anything of the sort.
>> >
>> > - Jonathan M Davis
>>
>> "you're only supposed to use it when you know what you're doing when you
>> use it"
>> Well, that's kinda the requirement for any feature, isn't it?... :P
>> Well, kinda, I do know what you mean. Yes, one needs to properly learn
>> how cast() works, but that doesn't mean it would not be better for the
>> feature to be designed in a way that is easier to learn (and just as
>> powerful to use), or actually, it doesn't mean that even if you do know
>> how cast() works, that you are not still likely to make a mistake when
>> using it.
>
> Really, you should only be using casts when you need a cast, and you  
> should be
> careful when you use them. So, you have to know what you're doing and  
> why in
> that particular instance and not use them willy-nilly. In most code,  
> casts
> should be quite rare. If you're doing a lot of low-level stuff, then they
> might be more common, but in general, they're a sledgehammer that  
> shouldn't be
> used except when you really need them.

Casting is the recommended way to determine if something is actually a  
derived type:

interface I {}

class C : I {}

void foo(I i) // change this to const(I) and you have a huge const bug!
{
    if(C c = cast(C)i)
    {
       // optimized branch
    }
    else
    {
       // default branch
    }
}

so it's not so easy to say you should "never" cast.  BTW, dcollections  
uses this quite a bit to support operations between multiple types of  
collections.

It would be nice if at least dynamic cast (with the added rules to prevent  
casting away const/immutable/shared) was a different syntax from cast,  
since it's a completely safe usage of casting (as long as you manually  
forward modifiers).  It's as safe as to! is when used with the right  
context.

-Steve


More information about the Digitalmars-d mailing list