Casting to interface not allowed in @safe code?

Jim jimwoo21680 at hotmail.com
Tue May 21 07:56:02 UTC 2019


On Tuesday, 21 May 2019 at 07:19:38 UTC, Marco de Wild wrote:
> On Tuesday, 21 May 2019 at 05:51:30 UTC, Jim wrote:
>> Hi,
>>
>> consider this:
>>
>> interface Base
>> {
>>   void setup();
>> }
>>
>> interface FeatureX
>> {
>>   void x();
>> }
>>
>> class Foo: Base, FeatureX
>> {
>>   void setup(){};
>>   void x(){};
>> }
>>
>> void main()
>> {
>>   Base foo = new Foo(); // This would be the result of a 
>> factory class
>>
>>   (cast(FeatureX)foo).x(); // 1
>> }
>>
>> 1) error: casting to interface FeatureX is not allowed in 
>> @safe code.
>>
>> Question: How to call foo.x in @safe code ?
>
> I got it compiling using `(cast(FeatureX)(cast(Foo)foo)).x();`, 
> but I don't really recommend it. As far as the compiler is 
> concerned, `Base` and `FeatureX` are not related in any way 
> (I'd still expect it to work though). I don't know the 
> circumstances of your problem (so some assumptions here), but 
> usually casting is not the best option. You are basically 
> overriding the type system manually. Some suggestions you can 
> evaluate:
> - Extend the base interface:
> interface FeatureX : Base { /+...+/}
> or
> interface Combined : FeatureX, Base {}
>
> - Change the factory class to return either Foo, FeatureX or a 
> templated type (if it's a more general factory class). This way 
> we can leverage the type system.
>
> - You can also make the cast @trusted, but that seems like it 
> kinda defeats the purpose of the function being @safe...
>

The problem I'm trying to solve is I've got to implement a few 
Backends and some features are present in one Backend and not in 
another, depending on the OS or the underlying library.

So the idea was to implement the Base interface for each Backend 
and then additionally the extra features but not those that 
wouldn't make sense or aren't present in the library.

In the Backend implementation I know that I'm always dealing with 
an object that implements the Base interface and all the Feature 
interfaces.

The point of the Base interface is to be able to store those 
objects into an array.

I could just put all those Features into the Base interface but 
then for a few Backends I would end up with a lot of functions 
that would return nothing or throw an exception.

The combined interfaces looks good. Thanks.

> ---
> Returning to the original point (the cast is disallowed in safe 
> code), I don't think it is listed in the spec: 
> https://dlang.org/spec/function.html#safe-functions Unless I am 
> missing some implementation details about interfaces, I would 
> expect it to work just like class casts (i.e. return null on a 
> failed cast, thereby having defined behaviour, thereby being 
> @safe).

That was my expectation as well. But since the 2 interfaces 
aren't related it kind of makes sense.


More information about the Digitalmars-d-learn mailing list