This is something I've toyed with in the past, but only recently considered using on a regular basis. I'll post a working example of some current brainstorm sessions, but until then, Id' like to know what you guys think about this approach?
This is something I've toyed with in the past, but only recently considered using on a regular basis. I'll post a working example of some current brainstorm sessions, but until then, Id' like to know what you guys think about this approach?
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
What exactly do you have in mind? You would still need the main function, methinks.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
I think it's quite good to have as little code as possible outside of classes. In my code, that usually means one function: main.
Normally, this function only has a try block with a call of a class function, and a catch block for all uncaught exception. I always catch std::exception and "..." and output a friendly message; sometimes I catch "ProgrammerException" to output a more specific error message. See, I have always a hierarchy of exceptions, first based on std::exception, then several others (ProgrammerException, EnvironmentException) and several based on that (AssertionFailedException, InvalidParameterException, InvalidPermissionsException, etc.).
I find this structure fairly readable, even if I return to a project months after I first wrote it.
Now, you'd like to completely remove main? That would only make the code less portable, as you'd have to write your own compiler or edit an open source compiler to load it. And just one single function in any file that does the same keeps it portable and readable.
You could just do what some libraries do and hide main() with a macro. Or just use Java.
"If you tell the truth, you don't have to remember anything"
-Mark Twain
It wouldn't require any compiler rewrites... After all the Linux kernel is written in C, has no main() function, and doesn't require a special compiler.
main() is just a part of standard C/C++. The C/C++ runtime calls it after initialization. With some adjustments to the runtime, some other function could be called (probably a static method of some class, like in Java). Not that I see any point in doing it.
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
A little off topic, but I suggest that you read:Originally Posted by EVOEx
How Non-Member Functions Improve Encapsulation
GotW #84: Monoliths "Unstrung"
Designing Simple Interfaces
Last edited by laserlight; 12-09-2008 at 12:51 PM. Reason: Added Stroustrup interview link.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
O.K., so for example:
And then instantiate like:Code:namespace xtd { namespace impl_ { struct application_base { application_base( void ) { if( singleton ) throw; singleton = this; } virtual int entry_point( char**, char** ) = 0; static application_base* singleton; }; application_base* application_base::singleton = 0; } // namespace impl_ template < typename Derived > struct application : public impl_::application_base { template < typename Pointer > Pointer sentinal_end( Pointer ptr ) { while( *ptr ) ++ptr; return ptr; } template < typename P1, typename P2, typename P3, typename A1, typename A2, typename A3 > int main_dispatcher( int ( Derived::* )( P1, P2, P3 ), A1 a1, A2 a2, A3 a3 ) { return ( ( Derived* )this )->main( a1, a2, a3 ); } template < typename P1, typename P2, typename A1, typename A2, typename A3 > int main_dispatcher( int ( Derived::* )( P1, P2 ), A1 a1, A2 a2, A3 a3 ) { ( ( Derived* )this )->main( a2, a3 ); } template < typename P1, typename A1, typename A2, typename A3 > int main_dispatcher( int ( Derived::* )( P1 ), A1 a1, A2 a2, A3 a3 ) { return ( ( Derived* )this )->main( a2 ); } template < typename A1, typename A2, typename A3 > int main_dispatcher( int ( Derived::* )( void ), A1 a1, A2 a2, A3 a3 ) { return ( ( Derived* )this )->main( ); } int entry_point( char** argv, char** envp ) { typename Derived::strings command_line( argv + 1, sentinal_end( argv + 1 ) ), environment_variables( envp, sentinal_end( envp ) ); return main_dispatcher( &Derived::main, argv[ 0 ], command_line, environment_variables ); } }; } // namespace xtd int main( int argc, char** argv, char** envp ) { if( !xtd::impl_::application_base::singleton ) throw; return xtd::impl_::application_base::singleton->entry_point( argv, envp ); }
Code:#include <iostream> #include <vector> using namespace std; struct application : xtd::application< application > { typedef vector< string > strings; int main( string const& name, strings const& commands, strings const& environment ) { cout << "Application: " << name << endl; if( !commands.empty( ) ) { cout << "- Command Line -" << endl; for( int i = 0, n = commands.size( ); i < n; i++ ) cout << i << ") " << commands[ i ] << endl; } if( !environment.empty( ) ) { cout << "- Environment Variables -" << endl; for( int i = 0, n = environment.size( ); i < n; i++ ) cout << i << ") " << environment[ i ] << endl; } } } instance;
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
I have made similar before. I actually made one that had a lofily constructed entry point. All the pre-entry time code I wrote in assembler. I like how you include environment variables though, that is rather crafty of you.
So you want to turn C++ into Java?? Why?
Stand-alone functions have a useful purpose. Forcing people to put everything into a class, whether it needs to be there or not is just stupid.
"I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008
"the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010
This seems rather repetitious given the other replies, but, C++ is supposed to be a generic programming language. While main as the entry point is a holdover from C, I don't think that you could create something substantially different (like a System class or whatever you call it) and still claim C++ to be a generic programming language. Imagine how annoying it is to use functional decomposition to solve a particular problem and then have to instantiate some class to get it to work.
There's probably something you could do, but is that different from just using Java?
>> What does this buy you?
Good question. First of all, it makes support for multiple platforms more seamless. You could define a WinMain function, for instance, and a simple change of linker options would be all that would be needed to convert to a Win32 executable. Customization of the format of command-line and environment-variables makes processing program data more straightforward. Putting everything in a class effectively places all of the code into a private namespace, and simplifies the initialization and access of data that would normally be declared as global variables. Those are the most obvious benefits, but there are other aesthetic and practical reasons for doing things this way. It's interesting that most of the objections I've heard so far seem to be based on the fear of the unfamiliar or unorthodox. I have yet to hear a truly compelling reason why this sort of paradigm should *not* be used...
Last edited by Sebastiani; 12-10-2008 at 09:26 AM. Reason: elaboration
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
Well, you've already used 'argv[0]' which is basically guaranteed to be useless on all platforms; I'd say you are on the right track.First of all, it makes support for multiple platforms more seamless.
The only difference between 'main' and 'WinMain' is the work and how much work is done before execution gets to the relevant function. You can have a single 'main' or a single 'WinMain' paired with more work in the middleware to handle both possibilities seamlessly.You could define a [...] convert to a Win32 executable.
You've displaced a trivial amount of work, not solved CLI interface issues.Customization of the [...] more straightforward.
Nothing you've done here would "normally be declared as global variables". But whether they might be or might not be doesn't really matter as all you've really done is wrap these normal global variables in a single global variable.Putting everything in a [...] global variables.
Aesthetic are always personal, but I'd love to see a single practical reason for changing the start point of application execution. You've done, basically, what Microsoft did. I'm fine with displacing work, even trivial work, but that doesn't require this change.Those are the most obvious benefits, but there are other aesthetic and practical reasons for doing things this way.
More than likely, you've heard valid, real-world concerns related to imposing designs or falsely licensing bad designs and simply interpreted them as you apparently have because you refuse to see the truth.It's interesting [...] unfamiliar or unorthodox.
At the end of the day, you've provided the work for about two lines of code by costing interoperability with other existing libraries that think hiding 'main' is a good idea, imposing bad design by requiring an otherwise pointless class to be written, falsely licensing bad designs by implying that you've done more than hide global variables in 'this', and even imposing an additional global where none be needed--even with this sort of thing.
To be fair, all the other methods of hiding 'main' are just as bad--though they may be bad in different ways. Instead of doing work to hide 'main' behind lies why not craft something that makes writing 'main' easier? And just in case you say "I intend to provide more than two lines of code worth of work before I release anything.": you still shouldn't hide 'main'. There is little work in typing:
But even then, the other issues still stand.Code:int main(int argc, char ** argv) { return(my_app_class(argc, argv)); }
Soma
C++ is not supposed to be a generic programming language. It is not supposed to be a programming language with only one paradigm at all.
It is supposed to be a multi-paradigm language! Generic programming may be a big part and one of its strengths, but that does not make C++ a generic programming language...
Well, that's more or less what I mean, sorry. Did you disagree with the point, or only my choice of words?