[D2.0] Transitive const is bad sometimes

eao197 eao197 at intervale.ru
Fri Sep 7 08:18:57 PDT 2007


	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 =  
m_clients.find( make_client_name( id ) );
         if( it != m_clients.end() )
           {
             client_name = it->first;
             state = 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 = [];
   };

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 ~= msg.data;
           }
       }

   private :
     ChannelState[string] channels;

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

// vim:ts=2:sts=2:sw=2: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 invocation  
in parallel.

That sample is not alone. I can provide more. For example,  
message-oriented framework. Message subscribes receive messages via const  
references. It is necessary, because subscribes can work on different  
threads. Because of that subscribes should not change message objects. But  
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



More information about the Digitalmars-d mailing list