www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [D2.0] Transitive const is bad sometimes

	Hi!

(sorry big code fragments)

I haven't seen any discussion about changes in conts/invariant model  =

recently, so I decided to remember that there are some situations where =
 =

transitive const is bad.

There is an extract from my code, which I was writting last days  =

(C++ version):

struct channel_state_t { ...; comm_buf_t m_outgoing_buffer; ... };
class ref_channel_state_t {...}; /* smart pointer for channel_state_t. *=
/

struct msg_send_package { ...; channel_id_t m_channel_id; comm_buf_t  =

m_data; ... };

class a_raw_incoming_channel_processor_t
   {
   private:
     typedef std::map< std::string, ref_channel_state_t > channels_map_t=
;
     channels_map_t m_clients;
     ...
   public :
     void
     evt_send_package( const msg_send_package & cmd )
       {
         std::string client;
         ref_channel_state_t state;
         if( try_find_channel( cmd.m_channel_id, client, state ) )
           {
             // Append outgoing data to outgoing buffer and initiate
             // channel write readyness detection.
             state->m_outgoing_buffer.append( cmd.m_data );
             ...
           }
       }

   private :
     /* This method doesn't change state of object so it is const */
     bool
     try_find_channel(
       const channel_id_t & id,
       std::string & client_name,
       ref_channel_state_t & state ) const
       {
         channels_map_t::const_iterator it =3D  =

m_clients.find( make_client_name( id ) );
         if( it !=3D m_clients.end() )
           {
             client_name =3D it->first;
             state =3D it->second;
           }
         return false;
       }
   ...
};

Class channel_state_t is used as a storage for various channels  =

descriptions. Method try_find_channel doesn't change object but returns =
 =

non-const reference to channel_state_t because channel_state_t is a  =

subject to modification.

In D 2.0 I can't make try_find_channel const method:

module demo;

import std.string;

class SendPackage
   {
   public :
     uint channel_id;
     byte[] data;
   }

class ChannelState
   {
   public :
     byte[] output_buffer =3D [];
   };

class ChannelsProcessor
   {
   public :
     void
     send_package(
       const(SendPackage) msg )
       {
         char[] client_name;
         ChannelState state;
         if( try_find_channel( msg.channel_id, client_name, state ) )
           {
             state.output_buffer ~=3D msg.data;
           }
       }

   private :
     ChannelState[string] channels;

     const bool
     try_find_channel(
       uint id,
       out char[] client_name,
       out ChannelState state )
       {
         client_name =3D .toString( id ).dup;
         if( client_name in channels )
           {
             state =3D channels[ client_name ];
             return true;
           }
         return false;
       }
   };

// vim:ts=3D2:sts=3D2:sw=3D2:expandtab

Because:

demo.d(45): Error: cannot implicitly convert expression  =

((this.channels)[cast(const(char)[])client_name]) of type const  =

ChannelState to demo.ChannelState

Yes I can make try_find_channel non-const. But suppose that there are  =

several auxilary methods those are called in send_package. If those  =

methods are const than compiler (or run-time) could made their invocatio=
n  =

in parallel.

That sample is not alone. I can provide more. For example,  =

message-oriented framework. Message subscribes receive messages via cons=
t  =

references. It is necessary, because subscribes can work on different  =

threads. Because of that subscribes should not change message objects. B=
ut  =

message objects sometimes should contain non-const references to some  =

other objects. Thus:

interface SystemShutdownNotifier
   {
     void
     addSubscriber( MessageReceiver subscriber );
     ...
   }

class MsgShutdownNotifierStarted : Message
   {
   public :
     SystemShutdownNotifier notifier;
   }

class SomeSubscriber : MessageReceiver
   {
   public :
     void
     onShutdownNotifierStarted(
       const(MsgShutdownNotifierStarted) cmd )
       {
          // Oops! I can't do that! :(
          cmd.notifier.addSubscriber( this );
       }
   }

So I propose to allow some exceptions from const transitivity.

-- =

Regards,
Yauheni Akhotnikau
Sep 07 2007