Friday, May 18, 2012

Many params in C++

I've been writing about business and sales for too long now.. it's unfortunately what I have to worry about every day.. but I'm still a programmer !

One thing that I've been doing for a while is passing parameters in a structure, when the parameters are too many.
This is nothing new. I think I remember the first usage from an Amiga function that did blit stretching. It was a later version of the OS and the function was pretty slow.. At the time, stretching a bitmap in real-time, was somewhat of a dream.. and it didn't help that Amiga had a bitplanes architecture, which made it extra painful to operate on pixels discretely.

But, anyhow, here's a sample case:

class Image
{
public:
    Image(
        u_int w,
        u_int h,
        u_int rowPitch,
        u_int depth,
        u_int chans,
        u_int flags=0,
        const U8 *pSrcData=NULL );
};

What we have here is a constructor with many parameters.
Two params clearly come with a default value, a third one "rowPitch" could be optional. But, because of how C++ works, we'd have to put it at the end grouped with the other parameters with default values, clearly imposing a dependency on which parameters can be truly optional.

Another thing that I don't like about this, is that it's easy to get confused:

Image img( 320, 240, 0, 32, 4, 0 );

..what is what ?
This gets worse when one starts overloading the constructor with versions that take a different series of parameters.

So, I prefer the following notation:

Image::Params par;
par.width   = 320;
par.height  = 240;
par.depth   = 32;
par.chans   = 4;
Image img( par );

Where the class Image is declared as:

class Image
{
public:
    class Params
    {
    public:
        u_int width;
        u_int height;
        u_int rowPitch;
        u_int depth;
        u_int chans;
        u_int flags;
        const U8 *pSrcData;

        Params() :
            width(0),
            height(0),
            rowPitch(0),
            depth(0),
            chans(0),
            flags(0),
            pSrcData(NULL)
        {
        }
    };

    Image( const Params &par );
};

The declaration is longer, but what matters is the usage.
It's obvious which parameters are being set and anything can be left to default.

The drawback is that sometimes some parameters really ought to be set for the constructor or function to work, and in some other cases some parameters could be mutually exclusive.
So, the constructor in this case will have to assert on the usage at run-time, which is not an ideal thing.
One option is to make the Params constructor itself require some parameters. For example, if width and height must always be specified, then Params would look like this:

Params( u_int width_, u_int height_ ) :
        width(width_),
        height(height_),
        rowPitch(0),

But, I'm not a big fan of this, and it doesn't work for all the cases (mutually exclusive params).

In conclusion, I find that passing parameters by "structure" sometimes helps to improve the code in C++ as well. It's not something new and it's common in Python and Objective-C (to some exent), but it's worth remembering that it's an option.

(Incidentally, I'm currently refactoring my image class 8)

See also the coding page.

10 comments:

  1. I like the "pubic" version too. :)

    class Image
    {
    pubic:
    ...

    ReplyDelete
  2. wow !! ...Freud strikes.. hard !!

    hohoho

    ReplyDelete
  3. Hi Davide,
    Another stupid question if I may ask:
    Is it possible - in your opinion - a software shader to move (based on a function) vertexes, points, surfaces, whatever at render time?
    Can a shader overload some mesh specific or mesh modifier classes?
    Thanks and have a nice week!
    Marius.

    ReplyDelete
  4. Hi Marius,

    What's possible in hardware is certainly possible in software 8)
    It's really up to the renderer.
    It gets tricky with global illumination, because normally geometry shaders are useful to generate a lot of temporary geometry that is good at screen size.. but with global illumination there's more than what's viewed on screen and it's not easy to decide how finely to tessellate an object and how long to keep the generated geometry in the internal renderer cache.
    This is why ray tracers tend not to work well with displacement mapping.

    ReplyDelete
  5. Hi Davide,
    Thank You!
    I was reading some of your works page and dude, You must live quite long!
    Actually you will have to, you were born too early.
    If it doesn't make any sense to you, then dude you're damn too smart for the time being! :-P
    That's how I feel.
    Hugs my dear friend,
    Marius.

    ReplyDelete
  6. Thanks for the compliments !

    I don't think that it's so much about being smart, as much as putting a lot of time into things and being stubborn 8)

    I definitely wish I were born in the year 3000 or so.. assuming that the world will be a better place.. but who knows.. it's possible that if life become too easy, people will just become lazy !

    ReplyDelete
  7. I remember Steve Jobs was also very kind and very stubborn like some of my friends :-P
    More stubborn people needed to make a better world though, with same humble kindness and generosity, same always straight characters,..
    .., sorry but no compliments included :-P
    Hugs,
    Marius.

    ReplyDelete
  8. Was Steve Jobs very kind ? Many say that he could be quite rude and demanding.. but who knows, people have many sides.. he seemed like a kind person after all. I'm definitely one of his fans 8)

    Anyhow, I don't plan to become that famous.. fame can be a big burden !

    maoooooooo
    Davide

    ReplyDelete
  9. Sorry to say that,
    you are f...ing smart Davide!
    I did not say that, you just are!
    And yes, it was his hidden side, especially after his 'friend' ate his liver,.., many haven't noticed that but, that killed him, he was deeply devoted to his friends as seen, to his death.
    Don't ask who that 'friend' was - I know who was - that doesn't show Jobs was fouled, it only prove he had full trust and confidence.
    That man is not a big man, that man is the darkest side of human kind.
    Shame on him!!!
    What you call famous, it is and may indeed become a really big burden, it is good you know that.
    Jobs never wanted be famous anyhow to anybody, what we perceived as 'fame' was his devotion to his - say - clients. They actually were the other side of his own, they were the side to communicate happiness, faith and good feelings.
    That's why he was almost always surrounded by friends, people interested in what he had to communicate.
    Rude may seem to those pretending they are something else which, he usually could easily notice.
    His only but only dream in his life, was to make people happy. It may sound unbelievable but, that was his only ever dream.
    Nothing about wealth or money, never ever!
    Try now to picture this imaginary scene:
    we are both good friends and our common best friend, by accident is trapped under a car.
    We both pull the car hard to release our friend but, for some reason you notice my side is getting lower, pushing our friend.
    You may say, 'wtf man, pull harder!' that sound demanding, isn't it?
    You may now realize why some may say he was demanding.
    He was also - like some stubborn people - very long periods of day time 'involved'.
    Hugs my Friend,
    take care of you and your loved ones,
    Marius.

    ReplyDelete
  10. well.. it was really sad that he passed away.. but nothing really goes away.. the changes that someone made will stick forever.

    Inspiring people is probably more important than anything else.. an individual is always limited by time and resources.. but ideas have no limits 8)

    ReplyDelete