I’m in the process of building an application which needs extensive logging of points in time at which certain events happen. For example when it renders a sequence of different shapes to the screen then we need a logfile with info like ‘shape A rendered to surface at time X, shape B rendered to surface at time Y, surface flipped at time C’ etc. in response to comments These names (A,B) should be meaningful and will either be user-defined (e.g. ‘MyGroupOfRectangles’) or automatically generated (like shape type + number, e.g. ‘Rectangle1’ or for bitmaps/avis/… use the filename). Main reason for this is that most of the time the logfile is going to be interpreted simply by the user reading it and quickly checking out if the sequence is doing what he/she wants to.
In order to make this happen it’s clear that at the moment the log function is invoked it needs to know the name of the shape it’s going to log about. One could just give any type of object which is going to be logged about a string member. However thinking about that there are some implementation- and design-wise questions which make me doubt that approach. But other approaches in turn have other problems.
The major question being (almost philosophical – I’m probably overthinking this): should an object know it’s own name? After all it’s merely an implementation detail here, used solely for logging – if I wouldn’t want to log Shapes by their name they wouldn’t need to be named at all.
So does it make sense to stuff the name in there as well, or would it be a better practice to keep a map somewhere which links object instances to a name? Something like
Map< Shape, string > shapeNames;
string NameForShape( Shape s )
{
return shapeNames.Contains( s ) ? shapeNames[ s ] : "<unnamed>";
}
This is very much unintrusive but does introduces some other potential problems in keeping the map up to date with existing shapes: should a shape be destructed, it’s name also has to be erased from the map.
The other option (or if there are multiple other options, by all means let me know) is to make a Shape returns it’s name. Being an interface it could be like this:
interface Shape
{
void Render();
...
string Name();
}
However this means every implementation has to take care of providing the Name()
implementation and they’re likely to going to be doing that all in the same way, like
class Rect : Shape
{
public:
Rect( string name ) : { this->name = name; }
string Name() { return name; }
private:
string name;
}
That’s quite some boilerplate and DRY is a holy rule so raises more questions: do I get rid of the pure interface and make it abstract instead (not ideal for unit testing)? Or do I add an extra layer with a default Shape implementation like NamedShape which partially implements Shape and just provides Name() (extra inheritance layer is not ideal either)?
6
What you’d like to have is a mixin, or a trait, but you can’t have it since your language of choice doesn’t support it. So you are looking for ways to emulate it.
Personally I agree that deriving an object’s name shouldn’t be its own responsibility. For one, because if your naming convention changes, you have to change your Rect.Name
implementation. So now the Rect
class an extra reason to change, which violates SRP.
Custom implementation of Object.toString
– brought up by @gnat in comments – can be tremendously helpful for debugging, but – perhaps it’s just my bias – I wouldn’t put anything actually important, any data worth of being persisted, into toString
.
Transferring the responsibility of naming objects in a clear manner into a class of its own sounds like a good idea.
Does it really have to keep track of every shape in existence, though? That’s what worries you, and I’m not sure why that would be a requirement.
Couldn’t this class simply derive reasonable names for any given Shape
on the fly? I may be missing some context here. You always know what type any particular Shape
instance is. Where are the A
, B
, C
identifiers coming from?
7
so, to recap:
- your shapes have actual names, determined by some outside entity (possibly user input), and aren’t always just
Circle1
etc. - you don’t think the shape should be responsible for this property (namedness? nominativity?)
Well, assuming you don’t use a global logger and the logger itself has a sane interface, you can create a named logger proxy: either that’s passed to the Shape constructor, or you wrap them both in a NamedShape which passes the proxy to each forwarded method.
Then, every line logged to the proxy is just forwarded to the real logger, with the name prepended.
0
Why don’t you just use RTTI to get a string representation of the class name directly? Yes, it is implementation defined, so you can’t depend on it being some exact thing if you are switching compilers. However if you need human readable logging, this is an excellent solution that doesn’t involve adding a line of code outside the Logger class itself.
https://stackoverflow.com/questions/1024648/retrieving-a-c-class-name-programatically
1