Thread: Use of a class in place of main( )?

  1. #1
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708

    Use of a class in place of main( )?

    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;
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    What exactly do you have in mind? You would still need the main function, methinks.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    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.

  4. #4
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    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

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by EVOEx View Post
    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.
    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);
    //}

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by EVOEx
    I think it's quite good to have as little code as possible outside of classes.
    A little off topic, but I suggest that you read:
    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.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    O.K., so for example:

    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 );
    }
    And then instantiate like:

    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;
    }

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Eeeewwwww!

    What does this buy you? O_o

    Soma

  9. #9
    Banned
    Join Date
    Dec 2008
    Posts
    49
    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.

  10. #10
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    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

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    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?

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> 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;
    }

  13. #13
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    First of all, it makes support for multiple platforms more seamless.
    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.

    You could define a [...] convert to a Win32 executable.
    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.

    Customization of the [...] more straightforward.
    You've displaced a trivial amount of work, not solved CLI interface issues.

    Putting everything in a [...] global variables.
    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.

    Those are the most obvious benefits, but there are other aesthetic and practical reasons for doing things this way.
    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.

    It's interesting [...] unfamiliar or unorthodox.
    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.

    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:

    Code:
    int main(int argc, char ** argv)
    {
        return(my_app_class(argc, argv));
    }
    But even then, the other issues still stand.

    Soma

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    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?
    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...
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Well, that's more or less what I mean, sorry. Did you disagree with the point, or only my choice of words?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with FIFO QUEUE
    By jackfraust in forum C++ Programming
    Replies: 23
    Last Post: 04-03-2009, 08:17 AM
  2. Checking array for string
    By Ayreon in forum C Programming
    Replies: 87
    Last Post: 03-09-2009, 03:25 PM
  3. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  4. Replies: 3
    Last Post: 10-31-2005, 12:05 PM