[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