|
Probably impossible, but is there any way to do this in C/C++? |
Chris Katko
Member #1,881
January 2002
|
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: |
SiegeLord
Member #7,827
October 2006
|
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 |
Jonatan Hedborg
Member #4,886
July 2004
|
Chris Katko said: 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
|
I didn't get it. [My website][CppReference][Pixelate][Allegators worldwide][Who's online] |
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"} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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
|
Johan Halmén said: 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: |
Arthur Kalliokoski
Second in Command
February 2005
|
I have to type "man blit" into the console. They all watch too much MSNBC... they get ideas. |
MiquelFire
Member #3,110
January 2003
|
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) --- |
Edgar Reynaldo
Major Reynaldo
May 2007
|
spam bot gone rogue leaves spammy ad for mobile jammers after joining allegro.cc https://www.allegro.cc/ My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
bamccaig
Member #7,536
July 2006
|
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Chris Katko
Member #1,881
January 2002
|
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: |
bamccaig
Member #7,536
July 2006
|
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
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
|
Chris Katko said: 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: -- |
Chris Katko
Member #1,881
January 2002
|
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: |
Edgar Reynaldo
Major Reynaldo
May 2007
|
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. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|