digitalmars.D - [D2.0] Transitive const is bad sometimes
- eao197 (147/147) Sep 07 2007 Hi!
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