OOP / language design question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • cctv.star@gmail.com

    #1

    OOP / language design question

    I was wondering, why you always have to remember to call bases'
    constructors explicitly from the derived class constructor? Why hasn't
    this been enforced by the language?

  • Rene Pijlman

    #2
    Re: OOP / language design question

    cctv.star@gmail .com:[color=blue]
    >I was wondering, why you always have to remember to call bases'
    >constructors explicitly from the derived class constructor? Why hasn't
    >this been enforced by the language?[/color]

    Probably because the language doesn't know whether the subclass wants to
    override its base class's constructor, or enhance it.

    --
    René Pijlman

    Comment

    • Diez B. Roggisch

      #3
      Re: OOP / language design question

      cctv.star@gmail .com wrote:
      [color=blue]
      > I was wondering, why you always have to remember to call bases'
      > constructors explicitly from the derived class constructor? Why hasn't
      > this been enforced by the language?[/color]

      I have another question for you: why does JAVA enforce that a constructor of
      a base-class must be called prior to everything else in the derived class's
      constructor? No way to do some computing for parameters that I want to pass
      to the parent constructor...


      Besides, this automatically base-constructor-calling only happens for the
      most trivial of cases - the no-argument-constructors.

      Regards,

      Diez

      Comment

      • Heiko Wundram

        #4
        Re: OOP / language design question

        Am Dienstag 25 April 2006 12:34 schrieb cctv.star@gmail .com:[color=blue]
        > I was wondering, why you always have to remember to call bases'
        > constructors explicitly from the derived class constructor? Why hasn't
        > this been enforced by the language?[/color]

        Because sometimes you don't want to call the base classes constructors? The
        Python zen says: "Better explicit than implicit," and in this case it hits
        the nail on the head. Better to see right away what your code does (the
        explicit call to the base class), than to have to work around calling a bases
        constructor if you don't want to call it.

        --- Heiko.

        Comment

        • cctv.star@gmail.com

          #5
          Re: OOP / language design question

          Diez B. Roggisch wrote:[color=blue]
          > I have another question for you: why does JAVA enforce that a constructor of
          > a base-class must be called prior to everything else in the derived class's
          > constructor?[/color]
          Well, I can imagine it's done to make sure that the base(s) are
          properly constructed. Sound s sensible to me.
          [color=blue]
          > No way to do some computing for parameters that I want to pass
          > to the parent constructor...[/color]

          Try this:

          Derived::Dreive d() : Base(calcParam1 (), calcParam2())
          ....
          [color=blue]
          > Besides, this automatically base-constructor-calling only happens for the
          > most trivial of cases - the no-argument-constructors.[/color]

          Well, the language can at least ensure that theconstructor is called -
          i.e. either call it automatically if it can be called without
          parameters, or fail with error.

          Comment

          • cctv.star@gmail.com

            #6
            Re: OOP / language design question


            Heiko Wundram wrote:[color=blue]
            > Because sometimes you don't want to call the base classes constructors?[/color]
            Sounds strange to me at the moment, but I'll try to adjust to this
            thought.
            [color=blue]
            > Python zen says: "Better explicit than implicit," and in this case it hits
            > the nail on the head. Better to see right away what your code does (the
            > explicit call to the base class), than to have to work around calling a bases
            > constructor if you don't want to call it.[/color]
            Thanks, that explains it somehow - at least, it's consistent with
            explicit "self".
            I think I'll need some shift in thinking after C++.

            Comment

            • Rene Pijlman

              #7
              Re: OOP / language design question

              cctv.star@gmail .com:[color=blue]
              >I think I'll need some shift in thinking after C++.[/color]

              +1 qotw

              --
              René Pijlman

              Comment

              • Diez B. Roggisch

                #8
                Re: OOP / language design question

                > Well, I can imagine it's done to make sure that the base(s) are[color=blue]
                > properly constructed. Sound s sensible to me.[/color]

                It often is - there are popular examples in python where missing a
                constructor will cause a program to fail spectacular. But is it _always_ a
                sensible thing to do? No. If you only want some code inherited, but set up
                the required constraints to do so yourself. Such things can't be expressed
                in C++/JAVA, but that doesn't mean they aren't the sensible solution in
                some cases.
                [color=blue][color=green]
                >> No way to do some computing for parameters that I want to pass
                >> to the parent constructor...[/color]
                >
                > Try this:
                >
                > Derived::Dreive d() : Base(calcParam1 (), calcParam2())
                > ...[/color]

                Oh, I know about that. however, there are limits to this. For example, you
                can't do anything that depends on constructors called before in case of
                multiple inheritance. And you are forced to create a static method to do
                so, which can be viewed as ugly as well.
                [color=blue]
                > Well, the language can at least ensure that theconstructor is called -
                > i.e. either call it automatically if it can be called without
                > parameters, or fail with error.[/color]

                Yes, it can do that because of static typing - in fact it will fail on a lot
                more of occasions with a compilation error.

                The question here is if you are willing to trade freedom of expressiveness
                against the proposed security of static typing. I found that I favor the
                former and can live without the latter.

                Diez

                Comment

                • Duncan Booth

                  #9
                  Re: OOP / language design question

                  cctv.star@gmail .com wrote:
                  [color=blue]
                  > Heiko Wundram wrote:[color=green]
                  >> Because sometimes you don't want to call the base classes constructors?[/color]
                  > Sounds strange to me at the moment, but I'll try to adjust to this
                  > thought.[/color]

                  It makes sense in more static languages such as C++. The base class is
                  initialised by the constructor, so you have to do everything possible to
                  ensure that initialisation is done before you actually try to use any part
                  of the base class. Weird things can still happen in C++ if you start
                  calling methods too soon (e.g. to calculate some of the base constructor's
                  parameters): you can find uninitialised member variables and you might not
                  get exactly the virtual methods you expected.

                  Python is more laid back about these things. The object itself already
                  exists when __init__ is first called. It already has a type, which
                  (unlike C++) isn't going to change part way through. All that is missing
                  are a few attributes, and if you try to access them too soon you'll get an
                  exception rather than a random value.

                  It makes sense therefore to give the programmer the scope to override the
                  expected sequence of initialisation for those rare cases where it actually
                  matters. The programmer also gets enough scope to shoot themselves in the
                  foot, but Python programmers are expected to be intelligent enough not to
                  do that accidentally.

                  Usually though, if a subclass doesn't immediately call the base class
                  constructors as the first thing it does in __init__ it indicates poor code
                  and should be refactored.

                  BTW, the same arguments apply to destructors: if you have a __del__ method
                  and need to call the base __del__ methods you have to do that manually as
                  well.

                  Comment

                  • bruno at modulix

                    #10
                    Re: OOP / language design question

                    Duncan Booth wrote:
                    (snip)[color=blue]
                    > Usually though, if a subclass doesn't immediately call the base class
                    > constructors as the first thing it does in __init__ it indicates poor code
                    > and should be refactored.[/color]

                    Not necessarily. It's a common case to have some computations to do/some
                    attributes to set in the derived class's __init__ before calling the
                    superclass's.

                    --
                    bruno desthuilliers
                    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                    p in 'onurb@xiludom. gro'.split('@')])"

                    Comment

                    • bruno at modulix

                      #11
                      Re: OOP / language design question

                      cctv.star@gmail .com wrote:[color=blue]
                      > I was wondering, why you always have to remember to call bases'
                      > constructors[/color]

                      <pedantic>
                      s/constructors/__init__/

                      the __init__() method is *not* the constructor. Object's instanciation
                      is a two-stage process: __new__() is called first, then __init__().
                      </pedantic>

                      --
                      bruno desthuilliers
                      python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                      p in 'onurb@xiludom. gro'.split('@')])"

                      Comment

                      • Carl Banks

                        #12
                        Re: OOP / language design question

                        cctv.star@gmail .com wrote:[color=blue]
                        > Heiko Wundram wrote:[color=green]
                        > > Because sometimes you don't want to call the base classes constructors?[/color]
                        > Sounds strange to me at the moment, but I'll try to adjust to this
                        > thought.[/color]

                        In Java and C++, classes have private members that can only be accessed
                        by the class itself (and, in C++, friends). In those languages, a base
                        constructor needs to be called to initialize the base class's private
                        members.

                        Python has no private members (except for the double underscore
                        thingies, which aren't that common). Unlike C++ and Java, the derived
                        class's __init__ can usually initialize all the base class's members,
                        and it's occasionally useful to do so.

                        I would agree it's a mistake to not call the base class's __init__
                        unless you're doing it deliberately. If you want a tool to catch those
                        mistakes, have a look at pychecker. It can inform you whenever the
                        base class __init__ is not called.

                        (However, I totally disagree that it's a good idea to always call it
                        first, though. I've written base class __init__s that expected the
                        subclass to provide initialization methods, and some of those methods
                        needed some subclass members to exist before they were called.)

                        Comment

                        • Duncan Booth

                          #13
                          Re: OOP / language design question

                          bruno at modulix wrote:
                          [color=blue]
                          > Duncan Booth wrote:
                          > (snip)[color=green]
                          >> Usually though, if a subclass doesn't immediately call the base class
                          >> constructors as the first thing it does in __init__ it indicates poor
                          >> code and should be refactored.[/color]
                          >
                          > Not necessarily. It's a common case to have some computations to
                          > do/some attributes to set in the derived class's __init__ before
                          > calling the superclass's.
                          >[/color]

                          I did only say 'usually'. Can you actually think of any good examples where
                          you have to set a derived attribute before you can call the base class
                          constructor? I can't, which is why I was a bit vague.

                          The base class is unlikely to depend on the derived class attributes, and
                          unless it does there should be no reason which you can't just call the base
                          __init__ straight away. Perhaps if the base __init__ calls an overridden
                          method, but at that point it sounds to me like something wants refactoring.

                          I can think that you might have to do some computations to calculate
                          parameters for the base __init__, but that is a separate issue.

                          Comment

                          • Carl Banks

                            #14
                            Re: OOP / language design question


                            bruno at modulix wrote:[color=blue]
                            > cctv.star@gmail .com wrote:[color=green]
                            > > I was wondering, why you always have to remember to call bases'
                            > > constructors[/color]
                            >
                            > <pedantic>
                            > s/constructors/__init__/
                            >
                            > the __init__() method is *not* the constructor. Object's instanciation
                            > is a two-stage process: __new__() is called first, then __init__().
                            > </pedantic>[/color]

                            You know, Python's __init__ has almost the same semantics as C++
                            constructors (they both initialize something that's already been
                            allocated in memory, and neither can return a substitute object). I
                            actually think constructors are misnamed in C++, they should be called
                            initializers (and destructors finalizers). The only thing is that C++
                            doesn't always call operator new when constructing objects, whereas
                            Python always calls __new__, so you can put some initialization in
                            __new__ if you want.

                            Other than that I'd say that Python __init__ is analogous to Java and
                            C++ constructors, but is not a constructor because C++ and Java
                            constructors are not constructors. :) And Java has pointers, not
                            references. :)

                            A-rose-by-any-other-name-ly yr's,

                            Carl Banks

                            Comment

                            • Duncan Booth

                              #15
                              Re: OOP / language design question

                              Carl Banks wrote:
                              [color=blue]
                              > You know, Python's __init__ has almost the same semantics as C++
                              > constructors (they both initialize something that's already been
                              > allocated in memory, and neither can return a substitute object).[/color]

                              There is a significant difference: imagine B is a base type and C a
                              subclass of B:

                              When you create an object of type C in Python, while B.__init__ is
                              executing self is an object of type C (albeit without all the attributes
                              you expect on your C).

                              In C++ when the B() constructor is executing the object is an object of
                              type B. It doesn't become a C object until the C() constructor is
                              executing.

                              In other words, the object is constructed in Python before any __init__ is
                              called, but in C++ it isn't constructed until after all the base class
                              constructors have returned.

                              Comment

                              Working...