Rant: Date and Time fall short of simplicity in D

Jonathan M Davis jmdavisProg at gmx.com
Sat Mar 30 01:22:30 PDT 2013


On Saturday, March 30, 2013 09:15:24 Artur Skawina wrote:
> On 03/30/13 07:12, Jonathan M Davis wrote:
> > On Friday, March 29, 2013 22:46:27 Steven Schveighoffer wrote:
> >> The issue is when you think you are invoking the opCast operator, but you
> >> inadvertently end up casting using the compiler's type-bypassing version.
> >> I agree the opCast call is safe, it's that its name coincides with the
> >> "throw all typechecks away" operator.
> > 
> > I'd have to experiment to see exactly what is and isn't accepted, but in
> > my
> > experience, the compiler rarely allows casting to or from structs without
> > opCast (the same with classes except for the inheritance tree). So, I
> > really don't think that there's much risk of accidentally using a cast on
> > a user- defined type and have it use the built-in cast operator.
> > 
> >> I don't think to should ignore opCast, or not use it, but there should be
> >> a way to hook 'to' without using opCast.  And most types should prefer
> >> that.
> > 
> > I really just don't see a problem here. If opCast is defined, it's
> > perfectly safe regardless of what would happen if you tried to cast
> > without opCast being defined. It's also the language-defined way to do
> > type conversions. And I really don't see any need to use anything else to
> > make std.conv.to work. By using opCast, there's a standard way to define
> > type conversion, and there's a standard way for it to hook into
> > std.conv.to, which seems way better to me than trying to support every
> > which way that a particular programmer wants to try and define a
> > conversion function. Clearly, you think that using opCast is a problem,
> > but I just don't agree. It's safe; it's standard; and it works.
>    struct S {
>       ubyte[] p;
>    }
> 
>    import std.stdio;
> 
>    void main() {
>       immutable a = S(null);
>       // ...
>       auto b = cast(S)a;
>       writeln(typeof(a.p).stringof);
>       writeln(typeof(b.p).stringof);
>    }
> 
> which can easily happen in generic code. And you can't tell w/o looking
> at the S implementation whether it's safe or not (with an appropriate
> opCast it could be).

You're casting away immutable. You pretty much have to assume that that's 
unsafe and should never do it unless you know exactly what's going on with the 
types involved. And no opCast is involved here, so I don't see how it's even 
relevant to the discussion.

> 'cast()' is special, so you can't even use a "safer" opCast like
> 
>    auto opCast(DT)() inout { return inout(DT)(this.tupleof); }
>    // or, more likely, returning some templated object instance
> 
> because a different return type is not accepted. Using a method
> 
>       auto b = a.opCast!S();
> 
> avoids these problems -- you only have to provide a correct a.opCast
> implementation and the compiler will then catch caller mistakes.
> 
> 'cast' /is/ dangerous, separating the safe operations from the
> potentially unsafe ones is desirable. Most of the bugs caused by
> mistakenly dropping 'const' etc wouldn't have happened if the explicit
> casts weren't there - because the compiler would have complained,
> forcing the coder to consider if the conversion really is necessary
> and how to handle it properly.

Built-in casts are dangerous. opCast is a completely different ballgame.

- Jonathan M Davis


More information about the Digitalmars-d mailing list