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








eao197 <eao197 intervale.ru>