Sign in to follow this  

Different names for functions that do the same?

This topic is 4474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys I'm trying to make my library (SDL_Config) as easy to use by end-coder as possible. Now I'm thinking whether it would be worth adding to those public API functions...

 int CFG_WriteBool( /* notimportant */ );
 int CFG_WriteInt( /* notimportant */ );
 int CFG_WriteFloat( /* notimportant */ );
 int CFG_WriteText( /* notimportant */ );


... few others, which would duplicate behaviour of those above, but would have slightly different names, ie.
                                             // Implemented in terms of:
 int CFG_WriteBoolean( /* notimportant */ ); // CFG_WriteBool
 int CFG_WriteInteger( /* notimportant */ ); // CFG_WriteInt
 int CFG_WriteString( /* notimportant */ );  // CFG_WriteText


So, it would became non important whether you call CFG_WriteInt() or CFG_WriteInteger() - both do the same. This way, end-user could use form which he likes most, he remembers, or he actually typed. So, at last he wouldn't be forced to use functions with names, that were created in library author's sick mind :-) What do you think about it? I care, since you're the potential user of this library [wink]. Single sentence will do.

Share this post


Link to post
Share on other sites
No. It will provide slightly more code-bloat (negligible, perhaps). It will create confusion between disparate users looking at each others' code when they use two different functions to do the same thing. Consistency is a must in code that is to be distributed.

Share this post


Link to post
Share on other sites
I for one value orthogonality. Why bother adding the new functions? They don't contribute. They just serve to muddy the waters, thereby defeating the entire point of a library, which is to make everything easier.

Share this post


Link to post
Share on other sites
Bad Idea(tm)
Look around at other popular libraries, and count how many times you see this done.
If you absolutely must do this, make sure to make the alternate names static inline functions in the header file, that merely wrap a call to the original function, as the compiler will then compile them out.

Share this post


Link to post
Share on other sites
My thoughts: Assuming that those functions actually write the type they say they do, then I'd prefer (only) the second version (or better yet just parameterize all of those so all I have to remember is CFG_Write()), and I really don't see a reason for doing this other than to create confusion down the line (I can always MACRO my own function names if I wanted to).

Share this post


Link to post
Share on other sites
Quote:
Original post by stylin
(or better yet just parameterize all of those so all I have to remember is CFG_Write())

The best idea we've heard so far.

Share this post


Link to post
Share on other sites
Quote:
Original post by TDragon
Quote:
Original post by stylin
(or better yet just parameterize all of those so all I have to remember is CFG_Write())

The best idea we've heard so far.


But SDL is written in ansi C, and C doesn't allow function overloading, so it would have to be something like void CFG_Write(void *value, uint32 length).

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by TDragon
Quote:
Original post by stylin
(or better yet just parameterize all of those so all I have to remember is CFG_Write())

The best idea we've heard so far.


But SDL is written in ansi C, and C doesn't allow function overloading, so it would have to be something like void CFG_Write(void *value, uint32 length).


The web page says C/C++, so I made an assumption.

Share this post


Link to post
Share on other sites
No, I personally don't need to have it, I wanted to introduce such functionality for the end-coder (to make his life easier). This idea came from this situation:

I was coding test program which uses SDL_Config. Everything was going fine, until I tried to compile it - several erros about "CFG_ReadInteger undeclared" appeared. I got little annoyed, since it was the way I was thinking: "I wanted to read integers", and so I misspelled CFG_ReadInt.

Then I gave a second thought to function names, especially why CFG_ReadInt is better than CFG_ReadInteger. I came to conclusion that they're equally good - so why should I discriminate people, who ie. are used to Pascal, and "integer" datatypes. So, I wanted to get best from two worlds - if you're addicted to C++ or don't like to write too much, you may use CFG_ReadInt. OTOH, if you like to use longer, more descriptive function names, and have no ambiguity whether that what you're trying to do it to read interrupt (CFG_ReadInt [wink] ), you can use CFG_ReadInteger - simple as that.

---

Hmmm, so it looks like you have some really good arguments against it (code bloat, ambiguity). Anyone else? Maybe someone is positive about this idea?

Share this post


Link to post
Share on other sites
Hmmm, good idea about that CFG_Write() thing. Though it's true that public API is written in C, there are going to be OOP wrappers after some time, when library finally matures. Then, if one will be using C++, he will have access to additional classess etc. and I'll probably add there some overloading stuff too.

Share this post


Link to post
Share on other sites
Quote:
Original post by Koshmaar
and I'll probably add there some overloading stuff too.


Don't forget namespaces while you're at it.

Share this post


Link to post
Share on other sites
Quote:
Effective C++ by Scott Meyers, Item 18: Strive for class interfaces that are complete and minimal:

...the more functions in an interface, the harder it is for potential clients to understand... A class with 10 functions looks tractable to most people, but a class with 100 functions is enough to make many programmers run and hide...

A large interface can also lead to confusion. Suppose you create a class that supports cognition for an artificial intelligence application. One of your member functions is called think, but you later discover that some people want the function to be called ponder, and others prefer the name ruminate. In an effort to be accomodating, you offer all three functions, even though they do the same thing... The client is faced with three different functions, all of which are supposed to do the same thing. Can that really be true? Isn't there some subtle difference...possibly in efficiency or generality or reliability? If not, why are there three different functions? ...such a potential client is likely to wonder what on earth you were thinking (or pondering, or ruminating over).

(If you haven't read Effective C++ you're missing out (ditto for Effective STL and More Effective C++).

Enigma

Share this post


Link to post
Share on other sites
I've read More Effective C++ ( though that was long time ago), but not first one (I've heard that it's targeted at people who are starting to learn C++). I generally agree with him, but...

Quote:
..such a potential client is likely to wonder what on earth you were thinking (or pondering, or ruminating over).


... such an user won't be thinking about it, if I'll describe it in the documentation.

...
...
...
(after a while)

Hmmmm, ok ok, no one ever reads documentation, I know, I know. Too bad, there are already many important things described.

Quote:

Don't forget namespaces while you're at it.


Don't worry :-)

Anyway, thanks guys for opinions, I'm not going to implement this idea. EOT?

Share this post


Link to post
Share on other sites

I'll use this thread to ask one more question, since it's naturally connected with what we were talking about so far.

Currently I have those functions that operate on single entries:


// for reading
CFG_ReadBool ()
CFG_ReadInt ()
CFG_ReadFloat()
CFG_ReadText ()

// for writing
CFG_WriteBool ()
CFG_WriteInt ()
CFG_WriteFloat()
CFG_WriteText ()



and


// removing
CFG_RemoveBoolEntry ()
CFG_RemoveIntEntry ()
CFG_RemoveFloatEntry()
CFG_RemoveTextEntry ()

// existance checking
CFG_BoolEntryExists ()
CFG_IntEntryExists ()
CFG_FloatEntryExists()
CFG_TextEntryExists ()



So, generally it goes like this: CFG_(Read|Write)(Bool|Int|Float|Text), CFG_(Bool|Int|Float|Text)EntryExists and CFG_Remove(Bool|Int|Float|Text)Entry.

As you see, there is little inconsistency in function names, some have "Entry" and some doesn't have it in their names.


I'd like to know what version would you, potential user [wink], personally prefer to use? Should I add "Entry" to read/write functions, or remove it from the other ones?

Share this post


Link to post
Share on other sites
My personal preference would be for you to remove it; the less typing I have to do, the better (not that I'll necessarily be using your library, but still...). Since the functions are already prefixed with CFG, it'll be obvious that you're operating on entries in the configuration file, I think.

With that in mind, is it even necessary to differentiate between types in the functions for EntryExists and RemoveEntry? If it would be possible for you to make generic "CFG_EntryExists" and "CFG_RemoveEntry" functions, that don't require you to know and/or specify the type, it seems like it would be easier on the endusers.

Cheers,
Twilight Dragon

Share this post


Link to post
Share on other sites
Quote:
My personal preference would be for you to remove it; the less typing I have to do, the better (not that I'll necessarily be using your library, but still...). Since the functions are already prefixed with CFG, it'll be obvious that you're operating on entries in the configuration file, I think.


To be honest, I also thought about it. What's more, is that all config file libs I checked, were using normal ReadXXX semantics etc.

But - my library has some other functions, that follow the convention of CFG_(DO)(WHERE), where DO = Open, Save, Select, Clear etc. and WHERE = File, Group and (to some extent) Entry, ie. CFG_OpenFile, CFG_SaveFile, CFG_SelectGroup, CFG_RemoveGroup etc. So, it would be more consistent to use Entry postfix in all functions that operate on single entries.

That's why I asked about it here - there are 2 possibilites, where neither is clearly better than other...

Quote:
With that in mind, is it even necessary to differentiate between types in the functions for EntryExists and RemoveEntry? If it would be possible for you to make generic "CFG_EntryExists" and "CFG_RemoveEntry" functions, that don't require you to know and/or specify the type, it seems like it would be easier on the endusers.


Hmmm, interesting point. So, do you suggest to replace them with new one, or to add new one to lib, without throwing out anything?

Share this post


Link to post
Share on other sites
I would suggest you replace the multiple type-specified functions with the new non-type-specified functions. Less confusion all around. End users are stupid creatures which are easily confused. ;)

Share this post


Link to post
Share on other sites
Sign in to follow this