I have a "tracker" class. This class tracks objects from a given input image. But in addition to this, there is another parameter that corresponds to a value used in generating the image. The tracker may want to suggest a new value for this parameter to get better results on the next iteration. It would be suggesting this new value for what ever generates the image.
I currently implement this via:
struct TrackResults{
double new_scene_generation_coefficient;
std::vector<Track> tracks;
}
class Tracker{
public:
TrackResults update(const Image& image, double scene_generation_coefficient){
// generate tracks and a new_scene_generation_coefficient
// ...
return {new_scene_generation_coefficient, tracks}
}
}
My intuition is that we don't want to modify the value directly and we want to avoid having the Tracker
depend on knowing about a class it only needs one value from, and could potentially change. I feel if I instead returned by reference here, I would potentially cause a cascading effect of anything that uses the tracker to depend on something it otherwise wouldn't need to, or pass around a mutable reference dangerously.
I don't find any issues in terms of maintainability with this, but there are some very slight ergonomic issues, for example, when I want tracks, I have to first go through TrackResult
object.
I'm concerned however, since this seems like a code smell, the values in the data class have nothing to do with each other, and there are no methods that would use both in tandem. In other posts people argue that there should be no data classes, since you should just be able to move functions that work on the members of the class into a method.
Another thing I should mention, is that Tracks is maintained internally any way. Tracks are returned by value to avoid messing with the internal structure of the class from outside actors (like loggers which exist in the real system). This makes me think that tracks should be queried after update
, and the new_scene_generation_coefficient
is the only thing that should be returned. Potentially however, there are more values that would need to be used to edit the object which generated the Image
in the first place, but at least these are related. An issue with the separate track query after update is that it becomes dangerous for the user, as there is no guarantee that they will try to query directly afterwards, and that even if they do, that they will get the state of the track list as it was when update()
was called. This seems like a code smell to require a user to call another method first in order use a separate method in this way.