Can we override [][] ?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jack Saalweachter

    #31
    Re: Can we override [][] ?

    Marcus Kwok wrote:[color=blue]
    > I actually read an article just today on how Hungarian notation itself
    > has become horribly bastardized, and it is this bad version of it that
    > everybody knows and many people dislike. Essentially, in the original
    > paper, the author (Charles Simonyi) used the word "type" instead of
    > "kind", and people took it too literally, thus destroying the original
    > usefulness.
    >
    > http://joelonsoftware.com/articles/Wrong.html
    > (near the bottom of the article)
    >[/color]
    Huh, that article totally changed my perspective on Hungarian Notation.

    The idea adding type-modifiers to a language has long seemed awesome to
    me; consider if (as in the example in the article above), you said:

    unsafe string a = Request("name") ;
    ...
    safe string b = a; // Type error; implicit conversion from 'unsafe'
    to 'safe', as illegal as modifying a 'const' object.

    Knowing that Hungarian Notation was /intended/ to be a work-around for
    extending the type system (since it's infinitely easier and almost as
    effective), rather than a simple parroting of the existing type system,
    makes it potentially useful in my mind.


    Jack Saalweachter

    Comment

    • Axter

      #32
      Re: Can we override [][] ?

      Earl Purple wrote:[color=blue]
      > Axter wrote:[color=green][color=darkred]
      > >> If you think your comments are constructive, then you're either[/color]
      > > ignorant, or have no manners. IMHO, it's most likely both.[/color]
      >
      > This is becoming too much of a flame war. But there was some
      > constructive criticism in there. Let me see if I can point it out:
      >
      > template < class T>
      > class dynamic_2d_arra y
      > {
      > public:
      > dynamic_2d_arra y(size_t row, size_t col):m_row(row) ,m_col(col),
      > m_data((row!=0& &col!=0)?new T[row*col]:NULL){}
      > dynamic_2d_arra y(const
      > dynamic_2d_arra y&src):m_row(sr c.m_row),m_col( src.m_col),
      > m_data((src.m_r ow!=0&&src.m_co l!=0)?new T[src.m_row*src.m _col]:NULL){
      > for(size_t r=0;r<m_row;++r )for(size_t c=0;c<m_col;++c ) (*this)[r][c]
      > = src[r][c];
      > }
      > ~dynamic_2d_arr ay(){if(m_data) delete []m_data;}
      > inline T* operator[](size_t i) {return (m_data + (m_col*i));}
      > inline T const*const operator[](size_t i) const {return (m_data +
      > (m_col*i));}
      > protected:
      > dynamic_2d_arra y& operator=(const dynamic_2d_arra y&);
      > private:
      > const size_t m_row;
      > const size_t m_col;
      > T* m_data;
      > };
      >
      > 1. No method to retrieve back the dimensions. Easy enough to modify.
      > Add in:
      >
      > size_t rows() const { return m_row; }
      > size_t cols() const { return m_col }[/color]

      As I previously stated, the sole purpose of the dynamic_2d_arra y, is to
      give the functionallity of a static size C-Style array that has a
      dynamic size.
      Since this is easy to add, IMHO, it's not needed for the example.
      [color=blue]
      > 2. protected section when class cannot be inherited. Minor detail but
      > operator= is automatically disabled for this class anyway due to it
      > having const members.[/color]
      Good point.
      [color=blue]
      > 3. no need to check for NULL in destructor[/color]
      Another good point.
      [color=blue]
      >
      > 4. To access the data you call matrix[0] which is unclear notation.[/color]
      I'm not sure what you mean there. Accessing an array via [][] is the
      standard notation for C/C++ code.
      [color=blue]
      > 5. Your copy constructor is probably slower than you think as you are
      > calculating the position a lot of times. But as the arrays are
      > identical in size you can do member-by-member copy.[/color]
      I think it would be hard to measure the perfromance difference, but
      considering it could simplify the class, it would probably be a good
      idea to do a std::copy instead of the two loops.
      [color=blue][color=green]
      >>If you're really[/color]
      > advanced you'll have an is_pod<> traits-style function and use memcpy
      > when is_pod returns true.[/color]

      I rather keep the class generic, and not have to rely on external
      functions like boost::is_pod. I don't like creating generic code that
      depends on third party libraries, even if it is boost.
      You would be surprise at how many C++ developers don't even know what
      boost is.
      [color=blue]
      > If you use a nested vector then resizing can be done with vector's
      > member resize() function.[/color]
      I posted another link that had example code that does just that.


      The above class has a resize functoin, which I added, and it uses
      vector.
      I recomend using the above vector approach over my original
      dynamic_2d_arra y class.
      But if you need contiguous buffer, then the dynamic_2d_arra y might be a
      better option.

      Thanks for the constructive critique. I've already removed the op= and
      the unnecessary check for NULL.

      Comment

      • Noah Roberts

        #33
        Re: Can we override [][] ?


        Axter wrote:
        [color=blue]
        > Thanks for the constructive critique. I've already removed the op= and
        > the unnecessary check for NULL.[/color]

        While you're at it why don't you add some whitespace.

        On the other hand...not having any definately makes your class more
        obfuscated and difficult to comprehend so perhapse it is more
        beneficial to beginners that you just don't. That way they won't be
        able to make sense of what you are doing and will go elsewhere.

        Comment

        • Martin Jørgensen

          #34
          Re: Can we override [][] ?

          Tomás wrote:[color=blue]
          > Tomás posted:[/color]
          -snip-[color=blue]
          > Taking Cy's trick on-board, you could change it to:
          >
          >
          > class ChessBoard {
          > public:
          >
          > class Square {
          > public:
          > enum SquareContents {
          > empty, pawn, castle, horse, bishop, queen, king } contents;
          >
          > Square &operator=( SquareContents const sc )
          > {
          > contents = sc;
          > return *this;
          > }
          > };
          >
          > Square squares[64];
          >
          >
          > Square *operator[](unsigned const x)
          > {
          > return squares + 8 * (x-1);
          > }
          >
          > };
          >
          > int main()
          > {
          > ChessBoard board;
          >
          > board[3][5] = ChessBoard::Squ are::bishop;
          > }[/color]

          I didn't understood how [3][5] got converted to Square *, since it only
          takes an unsigned const as argument?

          First you create a ChessBoard with an empty SquareContents, I guess?

          When you then assign something (bishop) to board[3][5] what happens then?

          I understand "return squares" is element 0 to which you add an offset.
          8*0 = 0, 8*1 = 8, 8*2 = 16, etc. How to insert a king in location 20?

          I'm wondering, that perhaps it's connected with return *this from
          &operator=, but it would be nice to see an explanation...?


          Best regards
          Martin Jørgensen

          --
          ---------------------------------------------------------------------------
          Home of Martin Jørgensen - http://www.martinjoergensen.dk

          Comment

          • Marcus Kwok

            #35
            Re: Can we override [][] ?

            Noah Roberts <roberts.noah@g mail.com> wrote:[color=blue]
            > Marcus Kwok wrote:[color=green]
            >> I actually read an article just today on how Hungarian notation itself
            >> has become horribly bastardized, and it is this bad version of it that
            >> everybody knows and many people dislike. Essentially, in the original
            >> paper, the author (Charles Simonyi) used the word "type" instead of
            >> "kind", and people took it too literally, thus destroying the original
            >> usefulness.
            >>
            >> http://joelonsoftware.com/articles/Wrong.html
            >> (near the bottom of the article)[/color]
            >
            > So basically it is saying things should be named based on what their
            > interface is no?[/color]

            I wouldn't necessarily say that it's based on their interface, but more
            on their intent or purpose. For example, in the article he talks about
            it in the context of a WYSIWYG word processor, which must distinguish
            between coordinates relative to the window and coordinates relative to
            the page layout. Prefixes start with either 'x' or 'y' (indicating
            horizontal or vertical coordinate) and either 'l' or 'w' (for "layout"
            or "window", respectively). Another common prefix is 'c' for "count",
            so a prefix of "cb" would indicate that this variable is used to count
            bytes.

            Then, if anywhere in your code you see a "xl = yw" or a "yl = cb", it
            should tell you that you're trying to mix logically different types,
            even though all of them may be implemented as ints.
            [color=blue]
            > For instance something that is a "Copier" might be
            > better named as a "CopierComm and" if it was in fact a "Command".
            > Instances of this class should reflect what they will do.[/color]

            I don't think this is quite the idea.
            [color=blue]
            > That makes sense to me but I debate whether HN is verbose enough for
            > that. I also believe classes and variable names should reflect what
            > they are meant to do but I like to be a little more verbose about it
            > most of the time.[/color]

            --
            Marcus Kwok
            Replace 'invalid' with 'net' to reply

            Comment

            • Jack Saalweachter

              #36
              Re: Can we override [][] ?

              Martin Jørgensen wrote:[color=blue]
              > I didn't understood how [3][5] got converted to Square *, since it only
              > takes an unsigned const as argument?[/color]

              This trick goes back a way to a standard programming trick they teach in
              schools (which isn't actually useful, but kind of clever).

              If you tell students in their first C programming class, "dynamicall y
              create a 2-d array, with size NxM", they'll do one of the following:

              char **array = malloc(N * sizeof(char*));
              for (int i = 0; i < N; ++i) {
              array[i] = malloc(M * sizeof(char));
              }

              and then access the array by saying 'array[i][j]'.

              or

              char *array = malloc(N * M * sizeof(char));

              and then access the array by saying 'array[i*M + j]'.


              In their second-year programming class, the students learn a trick, and
              they'll write the following:

              char *flatArray = malloc(N * M * sizeof(char));
              char **array = malloc(N * sizeof(char*));
              for (int i = 0; i < N; ++i) {
              array[i] = flatArray + i*M;
              }

              and then access the array by saying 'array[i][j]'.

              This combines the advantages of the first two ways: you have the easy
              access of the first way ('array[i][j]'), but when it comes time to clean
              up, you only have to free the two arrays (flatArray and array). In the
              first way, you had to remember to free all of the rows of the array; if
              you just say 'free(array)', you leak them.

              (The third year student would skip the extra variable 'flatArray', and
              just allocate the space in array[0]; the fourth year student would say,
              "Why the hell do I need a 2d array?")


              This C++ trick is really just the equivalent of the second-year C
              student's trick. However, instead of storing the second char** array
              internally, it creates entries from it whenever you ask for them.


              Jack Saalweachter

              Comment

              • Marcus Kwok

                #37
                Re: Can we override [][] ?

                Jack Saalweachter <saalweachter@p urdue.edu> wrote:[color=blue]
                > Marcus Kwok wrote:[color=green]
                >> I actually read an article just today on how Hungarian notation itself
                >> has become horribly bastardized, and it is this bad version of it that
                >> everybody knows and many people dislike. Essentially, in the original
                >> paper, the author (Charles Simonyi) used the word "type" instead of
                >> "kind", and people took it too literally, thus destroying the original
                >> usefulness.
                >>
                >> http://joelonsoftware.com/articles/Wrong.html
                >> (near the bottom of the article)
                >>[/color]
                > Huh, that article totally changed my perspective on Hungarian Notation.[/color]

                Yeah, me too, because before I saw this article I only knew about the
                less-useful "Systems Hungarian" as opposed to the more useful "Apps
                Hungarian", and thus had already discarded "[Systems] Hungarian
                Notation" as not very useful.
                [color=blue]
                > The idea adding type-modifiers to a language has long seemed awesome to
                > me; consider if (as in the example in the article above), you said:
                >
                > unsafe string a = Request("name") ;
                > ...
                > safe string b = a; // Type error; implicit conversion from 'unsafe'
                > to 'safe', as illegal as modifying a 'const' object.
                >
                > Knowing that Hungarian Notation was /intended/ to be a work-around for
                > extending the type system (since it's infinitely easier and almost as
                > effective), rather than a simple parroting of the existing type system,
                > makes it potentially useful in my mind.[/color]

                Yes, I never really saw the value in most situations of specifying the
                specific type of a variable either. The intended use gives you much
                greater information.

                --
                Marcus Kwok
                Replace 'invalid' with 'net' to reply

                Comment

                • Martin Jørgensen

                  #38
                  Re: Can we override [][] ?

                  Jack Saalweachter wrote:[color=blue]
                  > Martin Jørgensen wrote:[/color]
                  -snip-
                  [color=blue]
                  > This C++ trick is really just the equivalent of the second-year C
                  > student's trick. However, instead of storing the second char** array
                  > internally, it creates entries from it whenever you ask for them.[/color]

                  You didn't really answer my questions. I think location 20 would be
                  [3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted to
                  be sure.


                  Best regards
                  Martin Jørgensen

                  --
                  ---------------------------------------------------------------------------
                  Home of Martin Jørgensen - http://www.martinjoergensen.dk

                  Comment

                  • Jack Saalweachter

                    #39
                    Re: Can we override [][] ?

                    Martin Jørgensen wrote:[color=blue]
                    > You didn't really answer my questions. I think location 20 would be
                    > [3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted to
                    > be sure.[/color]
                    You are correct: I completely misunderstood what you were asking.

                    Deep down, it shouldn't matter how you access location 20; what gets
                    mapped to location 20 is effectively 'implementation defined'. The goal
                    of the chessboard class is to abstract away the array and just give you
                    array-like access; if you can say 'board[3][4]' to refer to a location
                    on the board, why would you ever want to try to refer to location 20 in
                    the underlying array?

                    Just to be mean, the chessboard class could implement its op[] like so:

                    Square *operator[](unsigned const x)
                    {
                    return squares + 8 * (8 - x - 1);
                    }

                    From the outside, the chessboard behaves the same; however, location 20
                    is no longer mapped to board[3][4].


                    Jack Saalweachter

                    Comment

                    • Tomás

                      #40
                      Re: Can we override [][] ?

                      Martin Jørgensen posted:

                      [color=blue][color=green]
                      >> board[3][5] = ChessBoard::Squ are::bishop;[/color][/color]

                      [color=blue]
                      > I didn't understood how [3][5] got converted to Square *, since it only
                      > takes an unsigned const as argument?[/color]


                      Analyse the following statement:


                      board[3][5] = ChessBoard::Squ are::bishop;


                      If you look up an operator precedence table, you'll see that it's
                      identical to:


                      ( board[3] )[5] = ChessBoard::Squ are::bishop;


                      It's plain to see that operator[] is applied to "board". If we look at
                      the definition of this member function, we see that it returns a Square*,
                      i.e. a pointer. So it becomes:

                      (p)[5] = ChessBoard::Squ are::bishop;


                      When you apply [] to an intrinsic type, it evaluates to:


                      *(p + 5) = ChessBoard::Squ are::bishop;


                      So, looking at it again from the start:

                      board[3] evaluates to a pointer to a Square.
                      The block brackets are then applied to the pointer in order to access
                      an element at a particular index relative to the original pointer value.


                      -Tomás

                      Comment

                      • Thomas J. Gritzan

                        #41
                        [OT] Re: Can we override [][] ?

                        Tomás schrieb:[color=blue]
                        > Jim Langston posted:
                        >
                        >[color=green]
                        >>union SPixel
                        >>{
                        >> struct {
                        >> unsigned char B, G, R, A;
                        >> };
                        >> unsigned long Value;
                        >>};[/color]
                        >
                        >
                        >
                        > Platform-specific code, I realise. (What you're trying to do can be quite
                        > easily achieved portably though.)
                        >
                        >
                        > However, even if you're guaranteed that:
                        >
                        > (1) "unsigned long" is four bytes.
                        > (2) Your target architecture is Bigendian.
                        >
                        > The compiler is still within its rights to put padding between any of B G
                        > R A.
                        >[/color]

                        The OP seems to operate on a little endian machine.

                        He (Jim Langston) wrote:[color=blue]
                        > // Lets just prove that Intel is Bigendian.[/color]

                        I hope the code does not depend on it. :-)

                        Thomas

                        Comment

                        • Earl Purple

                          #42
                          Re: Can we override [][] ?


                          Jack Saalweachter wrote:[color=blue]
                          > struct MagicInt {
                          > // operator overloads, constructors, etc, to make this class behave
                          > // as an integer.
                          > };
                          >
                          > std::pair<Magic Int, MagicInt> operator , (const MagicInt &a, const
                          > MagicInt& b) { return std::make_pair( a, b); }
                          >
                          > class Array2d {
                          > public:
                          > value& operator[](const std::pair<Magic Int, MagicInt> &a) {
                          > // use a.first and a.second to find the value...
                          > }
                          > };
                          >
                          > int main() {
                          > Array2d M(X, Y);
                          >
                          > for (MagicInt a = 0; a < X; ++a)
                          > for (MagicInt b = 0; b < Y; ++b)
                          > M[a, b] = i + j;
                          > }
                          >
                          >
                          > So, 'M[a, b]' is *implementable* , even if so brittlely that you'd never
                          > want to use it. (For instance, you cannot say 'M[1, 2]'.)
                          >
                          > Jack Saalweachter[/color]

                          Submit that to boost - all you have to do is implement MagicInt and it
                          will probably become part of their "not so important" libraries. (A bit
                          like lambda)

                          Comment

                          • Martin Jørgensen

                            #43
                            Re: Can we override [][] ?

                            Tomás wrote:[color=blue]
                            > Martin Jørgensen posted:
                            >
                            >
                            >[color=green][color=darkred]
                            >>> board[3][5] = ChessBoard::Squ are::bishop;[/color][/color]
                            >
                            >
                            >[color=green]
                            >>I didn't understood how [3][5] got converted to Square *, since it only
                            >>takes an unsigned const as argument?[/color]
                            >
                            >
                            >
                            > Analyse the following statement:
                            >
                            >
                            > board[3][5] = ChessBoard::Squ are::bishop;
                            >
                            >
                            > If you look up an operator precedence table, you'll see that it's
                            > identical to:
                            >
                            >
                            > ( board[3] )[5] = ChessBoard::Squ are::bishop;
                            >
                            >
                            > It's plain to see that operator[] is applied to "board". If we look at
                            > the definition of this member function, we see that it returns a Square*,
                            > i.e. a pointer. So it becomes:
                            >
                            > (p)[5] = ChessBoard::Squ are::bishop;
                            >
                            >
                            > When you apply [] to an intrinsic type, it evaluates to:
                            >
                            >
                            > *(p + 5) = ChessBoard::Squ are::bishop;
                            >
                            >
                            > So, looking at it again from the start:
                            >
                            > board[3] evaluates to a pointer to a Square.
                            > The block brackets are then applied to the pointer in order to access
                            > an element at a particular index relative to the original pointer value.[/color]

                            Thanks - I also thought it must be something like this....

                            Just another little thing:

                            Square &operator=( SquareContents const sc ) didn't have to return *this
                            for the program to work, did it?

                            I guess the reason for having "return *this" is that you can then do
                            something like (not that it might be a good idea here, but isn't it
                            possible):

                            ChessBoard b1, b2, b3;

                            b1[3][5] = b2[0][4] = b3[3][3] = ChessBoard::Squ are::bishop;

                            ?


                            Best regards
                            Martin Jørgensen

                            --
                            ---------------------------------------------------------------------------
                            Home of Martin Jørgensen - http://www.martinjoergensen.dk

                            Comment

                            • Martin Jørgensen

                              #44
                              Re: Can we override [][] ?

                              Jack Saalweachter wrote:[color=blue]
                              > Martin Jørgensen wrote:
                              >[color=green]
                              >> You didn't really answer my questions. I think location 20 would be
                              >> [3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted
                              >> to be sure.[/color]
                              >
                              > You are correct: I completely misunderstood what you were asking.
                              >
                              > Deep down, it shouldn't matter how you access location 20; what gets
                              > mapped to location 20 is effectively 'implementation defined'. The goal
                              > of the chessboard class is to abstract away the array and just give you
                              > array-like access; if you can say 'board[3][4]' to refer to a location
                              > on the board, why would you ever want to try to refer to location 20 in
                              > the underlying array?[/color]

                              Nobody wants that. It's just a matter of understanding the code.
                              [color=blue]
                              > Just to be mean, the chessboard class could implement its op[] like so:
                              >
                              > Square *operator[](unsigned const x)
                              > {
                              > return squares + 8 * (8 - x - 1);
                              > }
                              >
                              > From the outside, the chessboard behaves the same; however, location 20
                              > is no longer mapped to board[3][4].[/color]

                              That doesn't give any sense.

                              You changed:

                              "return squares + 8 * (x-1)" -> "return squares + 8 * (7 - x)"

                              Original case: x = 2 => 8, your case: x = 2 => 40.

                              What are you trying to do?


                              Best regards
                              Martin Jørgensen

                              --
                              ---------------------------------------------------------------------------
                              Home of Martin Jørgensen - http://www.martinjoergensen.dk

                              Comment

                              • Tomás

                                #45
                                Re: Can we override [][] ?

                                Martin Jørgensen posted:

                                [color=blue]
                                > Square &operator=( SquareContents const sc ) didn't have to return
                                > *this for the program to work, did it?[/color]


                                Not it didn't need to return a reference to itself, we could have had:

                                void &operator=( ...

                                But that wouldn't be very C++-like, because an assignment results in an
                                L-value in C++, e.g.:

                                a = b = c;


                                Just for some trivia, an assignment results in an R-value in C, so the
                                following is illegal in C:


                                a = b = c;

                                [color=blue]
                                > I guess the reason for having "return *this" is that you can then do
                                > something like (not that it might be a good idea here, but isn't it
                                > possible):
                                >
                                > ChessBoard b1, b2, b3;
                                >
                                > b1[3][5] = b2[0][4] = b3[3][3] = ChessBoard::Squ are::bishop;[/color]


                                Exactly.


                                -Tomás

                                Comment

                                Working...