Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Probably impossible, but is there any way to do this in C/C++?

This thread is locked; no one can reply to it. rss feed Print
Probably impossible, but is there any way to do this in C/C++?
Chris Katko
Member #1,881
January 2002
avatar

Verilog 2001 and SystemVerilog have an amazing feature. Pass by name.

Say you have:

void complex_function(int x, int y, int z, int object_ID, int state_ID, ...);

You can do:

void main()
{
int x = 3;
int y = 5;
int z = 26;
int t1 = 1001;
int t2 = 1020;

complex_function(.x(x), .y(y), .z(z), .t2(object_ID), .t1(state_ID));
}

Which accomplishes two things. 1, it allows you to arrange your arguments however is most convenient. And even more important, 2, it forces you and the compiler to know that the argument being passed is exactly what you intend into exactly the variable you intend.

No worry looking up the definition of blit, or other hard to remember definitions. And more importantly, zero chance of thinking you know it and getting it wrong.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

SiegeLord
Member #7,827
October 2006
avatar

Pretty much any problem you can think of, the sadists/masochists over at Boost will have came up with a "solution" for it. Alternatively, named parameter idiom always "works" too.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Jonatan Hedborg
Member #4,886
July 2004
avatar

No worry looking up the definition of blit, or other hard to remember definitions. And more importantly, zero chance of thinking you know it and getting it wrong

You really ought to get a better IDE if you have to actually look that up somewhere :/

OICW
Member #4,069
November 2003
avatar

I didn't get it.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Johan Halmén
Member #1,550
September 2001

A typical IDE code editor shows you the parameter list when you have typed blit(

{"name":"608133","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/2\/626294f92bd145e41efc83545a8700d5.png","w":432,"h":58,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/2\/626294f92bd145e41efc83545a8700d5"}608133

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Chris Katko
Member #1,881
January 2002
avatar

A typical IDE code editor shows you the parameter list when you have typed blit(

You know, that's true. I haven't used a good one in a long time and I forgot that side of it. One of the reasons I use Geany is that it's very fast and responsive, but perhaps I should look into a more exhaustive IDE.

That point aside, Pass by Name is still a very useful feature. So much so that in, say, Verilog, it's the proper way to do parameter passing.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Arthur Kalliokoski
Second in Command
February 2005
avatar

I have to type "man blit" into the console. :-/

They all watch too much MSNBC... they get ideas.

MiquelFire
Member #3,110
January 2003
avatar

Name parameter allows for optional parameters without having a bunch of overloads that C++ has (and they actually allow for more combinations than overloads allow actually)

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red
If anyone is of the opinion that there is no systemic racism in America, they're either blind, stupid, or racist too. ~Edgar Reynaldo

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

bamccaig
Member #7,536
July 2006
avatar

In practice, I'd say that named parameters are only relevant for extremely stable APIs, and in that case you will probably memorize the API and not need something like this. In cases where there are several optional parameters then I guess it could be useful. Often this is accomplished in dynamically-typed languages that support it with an objects' properties. The same thing can be accomplished in statically-typed languages, though it comes at the expense of having to know the parameter types. And if the option/parameter names ever change then it can domino into a lot of maintenance. I would generally avoid abusing this. Most of the time, filling in nothing/null/zero for optional parameters that you don't need should suffice well enough. If you find that your API is too complex or too much work with this then perhaps you need to rethink your API. You can always offer alternative overloads, or factories, etc.

Chris Katko
Member #1,881
January 2002
avatar

bamccaig said:

In practice, I'd say that named parameters are only relevant for extremely stable APIs, and in that case you will probably memorize the API and not need something like this. In cases where there are several optional parameters then I guess it could be useful. Often this is accomplished in dynamically-typed languages that support it with an objects' properties. The same thing can be accomplished in statically-typed languages, though it comes at the expense of having to know the parameter types. And if the option/parameter names ever change then it can domino into a lot of maintenance. I would generally avoid abusing this. Most of the time, filling in nothing/null/zero for optional parameters that you don't need should suffice well enough. If you find that your API is too complex or too much work with this then perhaps you need to rethink your API. You can always offer alternative overloads, or factories, etc.

All of your points are true. But imagine an API for creating your object in a game.

You have x, y, x_vel, y_vel, facing_direction, type_of_object, object_ID, and more.

spawn(0, 0, 0, 0, DIR_NORTH, OBJ_TELEPORTER, 100012, 0,0,0,0,0,0,0,0,0,0,...many optional parameters);

Isn't super confusing, but:

spawn(0,0) :
   velocity(2.5, 2.5),
   direction(DIR_NORTH),
   ID(10015)

is pretty sweet for not bothering with optionals, and the exact variables/methods being used are clear. Which is very useful for people who are maintaining other people's code. It helps clarify what's going on. There's also no chance of accidentally removing one too many ",0" and ending up with a run time error.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

bamccaig
Member #7,536
July 2006
avatar

Perhaps, but in a language that is known for relative speed this level of dynamic magic comes at a significant cost. It basically forces you to assess why you're using a static language at all if what you really want is dynamic. Proper dynamic languages do it much simpler and will be much less error-prone. They can also generally be bound closely to the metal with some C glue where appropriate.

As a rule, I'd say that if your constructor/initializer (or any "subroutine" in the general sense) has an unreasonable number of parameters then it's probably also a sign that you're doing it wrong and that your "thing" has too much responsibility. Also keep in mind that a "factory" object is a good solution for centralizing the simplification of a mess for you. It lets you put it in one place, and reap the benefits of a simplified interface, without negatively affecting the design of the "real" thing.

I encourage you to experiment anyway because that's the only way that you'll be able to assess their fitness for a particular purpose. That said, if what you want is something more dynamic then consider a dynamically-typed language. I think it's pretty well established these days that Real(tm) programmers use the best tool for the job, and that even "scripting" languages are programming languages.

Peter Wang
Member #23
April 2000

You could always pass a struct. With C99:

f((params_t){.y = 1, .x = 1});

Yeah, not quite.

bamccaig said:

It basically forces you to assess why you're using a static language at all if what you really want is dynamic.

readable != dynamic

Quote:

Proper dynamic languages do it much simpler and will be much less error-prone.

less error-prone != dynamic

Kitty Cat
Member #2,815
October 2002
avatar

All of your points are true. But imagine an API for creating your object in a game.

You have x, y, x_vel, y_vel, facing_direction, type_of_object, object_ID, and more.

spawn(0, 0, 0, 0, DIR_NORTH, OBJ_TELEPORTER, 100012, 0,0,0,0,0,0,0,0,0,0,...many optional parameters);

Isn't super confusing, but:

spawn(0,0) :
   velocity(2.5, 2.5),
   direction(DIR_NORTH),
   ID(10015)

Problem is that parameter names in function declarations are completely superfluous in C/C++. It's completely valid to declare the same function multiple times, each with different parameter names. You don't even need to give a name to a parameter in a declaration (or definition in C++, if you don't use the parameter).

As for your example, I think the "proper" C++ way would be something like:
object.spawn(0,0).velocity(2.5, 2.5).direction(DIR_NORTH).ID(10015);
Each member function would return a reference to (or copy of) itself, which allows you to call another setter, etc, and get the resulting object.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Chris Katko
Member #1,881
January 2002
avatar

Kitty Cat said:

Problem is that parameter names in function declarations are completely superfluous in C/C++. It's completely valid to declare the same function multiple times, each with different parameter names. You don't even need to give a name to a parameter in a declaration (or definition in C++, if you don't use the parameter).

It's not that pass-by-name should be always used. It's that I think it should be an option naturally supported by the compiler/language instead of having to write templates to add functionality missing from the language itself. Once you use an in-language thing to model something that should be internal, you end up with template error messages that are extremely cryptic and long for the simplest error. You also lose the ability for the compiler to handle the "non-standard language feature" in the most optimal-to-date way. A compiler can't understand your additions to a language, so it can't optimize it the way it can if it was explicit.

Even the "worst thing ever" the goto statement is still in C/C++ because it has occasional uses where traditional branching would explode trying to model it.

So I don't see any drawback to supporting something that goes all the back to ALGOL in 1960 if it leads to cleaner syntax for situations that are complex without it. Especially functions with many optional parameters.

That being said, I never started this thread expecting someone to write a letter to the C++ committee.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Kitty Cat said:

As for your example, I think the "proper" C++ way would be something like:

object.spawn(0,0).velocity(2.5, 2.5).direction(DIR_NORTH).ID(10015);

Each member function would return a reference to (or copy of) itself, which allows you to call another setter, etc, and get the resulting object.

While this is nice, these are just setters and they leave the object incompletely initialized until every setter is used. It's just a trick. You need to use a constructor, because they allow both for member initialization, and parameters as well.

Go to: