Expressions in C#...

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

    #1

    Expressions in C#...

    Hi!

    I noticed a very funny behaviour when overloading operators
    on objects in C#:

    MyOjbects a,b,c,d;
    ....
    //objects are created and initalized here...
    ....
    b.Length = 100;
    c.Length = 100;

    for (i = 0; i < 10000; i++)
    {
    a = MyFun(2*c)*b;
    }

    Inside the overladed multiplication operator, I check:

    if (Op1.Length == Op2.Length) throw....

    And the exception triggers after about 100 iterations...!! ?
    Somehow the internal objects of the temporary variable
    created by 2*c passed to MyFun are being
    garbage collected (nullified) before the temporary variable is used for
    the first time...

    Are there some known issues with this?

    Thanks!
    Atmapuri


  • Atmapuri

    #2
    Re: Expressions in C#...

    Hi!

    The fix for the problem is to write the expression as:

    d = 2*c;
    a = MyFun(d)*b;

    That is to explicitely allocate the temporary variable....
    But of course, that is not really a fix, it just points to
    the problem...

    Thanks!
    Atmapuri




    "Atmapuri" <dip@community. nospamwrote in message
    news:ejuMK1B0GH A.4044@TK2MSFTN GP04.phx.gbl...
    Hi!
    >
    I noticed a very funny behaviour when overloading operators
    on objects in C#:
    >
    MyOjbects a,b,c,d;
    ...
    //objects are created and initalized here...
    ...
    b.Length = 100;
    c.Length = 100;
    >
    for (i = 0; i < 10000; i++)
    {
    a = MyFun(2*c)*b;
    }
    >
    Inside the overladed multiplication operator, I check:
    >
    if (Op1.Length == Op2.Length) throw....
    >
    And the exception triggers after about 100 iterations...!! ?
    Somehow the internal objects of the temporary variable
    created by 2*c passed to MyFun are being
    garbage collected (nullified) before the temporary variable is used for
    the first time...
    >
    Are there some known issues with this?
    >
    Thanks!
    Atmapuri
    >

    Comment

    • Marc Gravell

      #3
      Re: Expressions in C#...

      Sounds curious; can you reproduce this in simple (yet complete), postable
      code?

      Is it possible that MyFun is return an MyOjbects [sic] instance that
      genuinely has the same length as b (100)? Equally, depending on whether
      these are structs or classes, it might be that you are (in the non-shown
      code) accidentally changing properties of the operands, and this behaviour
      is a side-effect?

      Marc


      Comment

      • Nicholas Paldino [.NET/C# MVP]

        #4
        Re: Expressions in C#...

        That's actually very, very wrong. Something else is going on here. The
        temporary variable that is created as a result of calling 2 * c isn't being
        GC'ed because the reference is held on the stack (through the parameter)
        when you pass it to MyFun.

        It is most definitely something else. Without seeing the code for the
        class where the operator is overloaded, as well as the code for MyFun, it's
        impossible to say.


        --
        - Nicholas Paldino [.NET/C# MVP]
        - mvp@spam.guard. caspershouse.co m

        "Atmapuri" <dip@community. nospamwrote in message
        news:ejuMK1B0GH A.4044@TK2MSFTN GP04.phx.gbl...
        Hi!
        >
        I noticed a very funny behaviour when overloading operators
        on objects in C#:
        >
        MyOjbects a,b,c,d;
        ...
        //objects are created and initalized here...
        ...
        b.Length = 100;
        c.Length = 100;
        >
        for (i = 0; i < 10000; i++)
        {
        a = MyFun(2*c)*b;
        }
        >
        Inside the overladed multiplication operator, I check:
        >
        if (Op1.Length == Op2.Length) throw....
        >
        And the exception triggers after about 100 iterations...!! ?
        Somehow the internal objects of the temporary variable
        created by 2*c passed to MyFun are being
        garbage collected (nullified) before the temporary variable is used for
        the first time...
        >
        Are there some known issues with this?
        >
        Thanks!
        Atmapuri
        >

        Comment

        • Atmapuri

          #5
          Re: Expressions in C#...

          Hi!
          Sounds curious; can you reproduce this in simple (yet complete), postable
          code?
          Could be a tough job. The garbage collector is not deterministic.. ..
          Is it possible that MyFun is return an MyOjbects [sic] instance that
          genuinely has the same length as b (100)? Equally, depending on whether
          these are structs or classes, it might be that you are (in the non-shown
          code) accidentally changing properties of the operands, and this behaviour
          is a side-effect?
          The code inside the loop works for 100 iterations and than fails?
          This is C#. It should be impossible especially because the next
          iteration does not depend upon the previous...

          Struct works fine and classes fail...

          Regards!
          Atmapuri



          Comment

          • Atmapuri

            #6
            Re: Expressions in C#...

            Hi!

            It would be very difficult for me to post the code.
            Can you think of anything why this would occur
            considering that:

            It works with struct but not with classes. I noticed
            that the compiler copies the struct before passing it
            to the function.

            MyObjects has a finalizer declared. And the only
            way I can imagine for the Length to be set to zero
            is if that finalizer has been called on the temporary
            object created by 2*c, before the object was used.

            Thanks!
            Atmapuri



            "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
            message news:%23M7SAaC0 GHA.1568@TK2MSF TNGP03.phx.gbl. ..
            That's actually very, very wrong. Something else is going on here.
            The temporary variable that is created as a result of calling 2 * c isn't
            being GC'ed because the reference is held on the stack (through the
            parameter) when you pass it to MyFun.
            >
            It is most definitely something else. Without seeing the code for the
            class where the operator is overloaded, as well as the code for MyFun,
            it's impossible to say.
            >
            >
            --
            - Nicholas Paldino [.NET/C# MVP]
            - mvp@spam.guard. caspershouse.co m
            >
            "Atmapuri" <dip@community. nospamwrote in message
            news:ejuMK1B0GH A.4044@TK2MSFTN GP04.phx.gbl...
            >Hi!
            >>
            >I noticed a very funny behaviour when overloading operators
            >on objects in C#:
            >>
            >MyOjbects a,b,c,d;
            >...
            >//objects are created and initalized here...
            >...
            >b.Length = 100;
            >c.Length = 100;
            >>
            >for (i = 0; i < 10000; i++)
            >{
            > a = MyFun(2*c)*b;
            >}
            >>
            >Inside the overladed multiplication operator, I check:
            >>
            >if (Op1.Length == Op2.Length) throw....
            >>
            >And the exception triggers after about 100 iterations...!! ?
            >Somehow the internal objects of the temporary variable
            >created by 2*c passed to MyFun are being
            >garbage collected (nullified) before the temporary variable is used for
            >the first time...
            >>
            >Are there some known issues with this?
            >>
            >Thanks!
            >Atmapuri
            >>
            >
            >

            Comment

            • Marc Gravell

              #7
              Re: Expressions in C#...

              It should be impossible especially because the next
              iteration does not depend upon the previous...
              In your example, with classes, it really, really *does*; the variables b & c
              are declared and initialised *outside* of the loop, so if you are causing
              side-effects in the objects then it will persist between iterations, and can
              (when some critical condition [determined by the exact foobar] is met) cause
              it to bomb. *Especially* for classes. For structs (without "ref" usage), the
              memory contents will be cloned when passing between stack contexts, so any
              side effect in the memory will only live as long as that stack - which
              probably explains why structs appear to work. You just "get lucky" with
              structs, in that they don't propegate bugs as readily. But the bug may still
              be there. I reckon that at some point you are monkeying with the contents of
              the class without cloning it first. As an example of a possible foobar
              (operator with operand side-effects):

              SomeClass operator *(SomeClass lhs, SomeClass rhs) {
              lhs.Length *= rhs;
              return lhs
              }

              This should be:

              SomeClass operator *(SomeClass lhs, SomeClass rhs) {
              SomeClass result = lhs.Clone();
              result.Length *= rhs;
              return result;
              }

              Marc


              Comment

              • Christof Nordiek

                #8
                Re: Expressions in C#...

                Why do you think, the result depends on garbage collection?
                The result of an operator shouldn't depent on instances ont referenced
                (directly or inderectly)
                by the operands. So it shouldn't depend on the existence of objetcs eligable
                for collection.

                "Atmapuri" <dip@community. nospamschrieb im Newsbeitrag
                news:e1rcmeC0GH A.1292@TK2MSFTN GP03.phx.gbl...
                Hi!
                >
                >Sounds curious; can you reproduce this in simple (yet complete), postable
                >code?
                >
                Could be a tough job. The garbage collector is not deterministic.. ..
                >
                >Is it possible that MyFun is return an MyOjbects [sic] instance that
                >genuinely has the same length as b (100)? Equally, depending on whether
                >these are structs or classes, it might be that you are (in the non-shown
                >code) accidentally changing properties of the operands, and this
                >behaviour
                >is a side-effect?
                >
                The code inside the loop works for 100 iterations and than fails?
                This is C#. It should be impossible especially because the next
                iteration does not depend upon the previous...
                >
                Struct works fine and classes fail...
                >
                Regards!
                Atmapuri
                >
                >
                >

                Comment

                • Atmapuri

                  #9
                  Re: Expressions in C#...

                  Hi!
                  In your example, with classes, it really, really *does*; the variables b &
                  c
                  b and c are not modified inside of the loop and also not inside
                  of the operator. That is certain. This also does not account for
                  undeterministic
                  nature of the problem. If I debug the stuff, it works fine... It only
                  fails when being run free... only after about 100 iterations...
                  and only if the temporary variable is not assigned explicitely, but
                  the expression is passed directly to the function as a parameter.
                  (I double tested that...)
                  SomeClass operator *(SomeClass lhs, SomeClass rhs) {
                  lhs.Length *= rhs;
                  return lhs
                  }
                  >
                  This should be:
                  >
                  SomeClass operator *(SomeClass lhs, SomeClass rhs) {
                  SomeClass result = lhs.Clone();
                  result.Length *= rhs;
                  return result;
                  }
                  That is a deterministic case.. that will fail in the first loop.

                  Thanks!
                  Atmapuri


                  Comment

                  • Atmapuri

                    #10
                    Re: Expressions in C#...

                    Hi!
                    Why do you think, the result depends on garbage collection?
                    The result of an operator shouldn't depent on instances ont referenced
                    (directly or inderectly)
                    by the operands. So it shouldn't depend on the existence of objetcs
                    eligable for collection.
                    The iteration count at which the error happens is not fixed...
                    The loop will execute fine 100x and fail on 101 for example.
                    That points to the garbage collector, because the time at which
                    the garbage collector is run is determined by the CLR.

                    And it is a predictive pattern. Whenever you have a expression
                    passed directly to the function without assigning its result first to the
                    local variable. (which should not matter).

                    Thanks!
                    Atmapuri


                    Comment

                    • Nicholas Paldino [.NET/C# MVP]

                      #11
                      Re: Expressions in C#...

                      Without seeing the code for the things I mentioned, it's nearly
                      impossible. You might as well post it, otherwise, no one will be able to do
                      much but offer conjecture at this point.

                      --
                      - Nicholas Paldino [.NET/C# MVP]
                      - mvp@spam.guard. caspershouse.co m

                      "Atmapuri" <dip@community. nospamwrote in message
                      news:%235y5boC0 GHA.1256@TK2MSF TNGP02.phx.gbl. ..
                      Hi!
                      >
                      It would be very difficult for me to post the code.
                      Can you think of anything why this would occur
                      considering that:
                      >
                      It works with struct but not with classes. I noticed
                      that the compiler copies the struct before passing it
                      to the function.
                      >
                      MyObjects has a finalizer declared. And the only
                      way I can imagine for the Length to be set to zero
                      is if that finalizer has been called on the temporary
                      object created by 2*c, before the object was used.
                      >
                      Thanks!
                      Atmapuri
                      >
                      >
                      >
                      "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                      in message news:%23M7SAaC0 GHA.1568@TK2MSF TNGP03.phx.gbl. ..
                      > That's actually very, very wrong. Something else is going on here.
                      >The temporary variable that is created as a result of calling 2 * c isn't
                      >being GC'ed because the reference is held on the stack (through the
                      >parameter) when you pass it to MyFun.
                      >>
                      > It is most definitely something else. Without seeing the code for the
                      >class where the operator is overloaded, as well as the code for MyFun,
                      >it's impossible to say.
                      >>
                      >>
                      >--
                      > - Nicholas Paldino [.NET/C# MVP]
                      > - mvp@spam.guard. caspershouse.co m
                      >>
                      >"Atmapuri" <dip@community. nospamwrote in message
                      >news:ejuMK1B0G HA.4044@TK2MSFT NGP04.phx.gbl.. .
                      >>Hi!
                      >>>
                      >>I noticed a very funny behaviour when overloading operators
                      >>on objects in C#:
                      >>>
                      >>MyOjbects a,b,c,d;
                      >>...
                      >>//objects are created and initalized here...
                      >>...
                      >>b.Length = 100;
                      >>c.Length = 100;
                      >>>
                      >>for (i = 0; i < 10000; i++)
                      >>{
                      >> a = MyFun(2*c)*b;
                      >>}
                      >>>
                      >>Inside the overladed multiplication operator, I check:
                      >>>
                      >>if (Op1.Length == Op2.Length) throw....
                      >>>
                      >>And the exception triggers after about 100 iterations...!! ?
                      >>Somehow the internal objects of the temporary variable
                      >>created by 2*c passed to MyFun are being
                      >>garbage collected (nullified) before the temporary variable is used for
                      >>the first time...
                      >>>
                      >>Are there some known issues with this?
                      >>>
                      >>Thanks!
                      >>Atmapuri
                      >>>
                      >>
                      >>
                      >
                      >

                      Comment

                      • Christof Nordiek

                        #12
                        Re: Expressions in C#...

                        Hi,

                        if your class has a finalizer and you supose the problem is because of
                        GC-timing you could try to debug when the finalizer ist called.

                        If the problem doesn't occur with structsit could be a problem
                        with sides effects. You should never change the operands inside
                        a operator. Also MyFunc looks like a Method that computes a
                        new value and shouldn't change the argument in any way.

                        BTW, why are you using a finalizer at all?
                        Finalizer should only clean up unmanaged resources. Managed
                        resources will be finalized themselves if they are referenced only by
                        objects eligable for finalization.
                        Maybe you try to clean smoething up wich shouldn't be and thereby
                        destroy something.

                        hth

                        "Atmapuri" <dip@community. nospamschrieb im Newsbeitrag
                        news:%235y5boC0 GHA.1256@TK2MSF TNGP02.phx.gbl. ..
                        Hi!
                        >
                        It would be very difficult for me to post the code.
                        Can you think of anything why this would occur
                        considering that:
                        >
                        It works with struct but not with classes. I noticed
                        that the compiler copies the struct before passing it
                        to the function.
                        >
                        MyObjects has a finalizer declared. And the only
                        way I can imagine for the Length to be set to zero
                        is if that finalizer has been called on the temporary
                        object created by 2*c, before the object was used.
                        >
                        Thanks!
                        Atmapuri
                        >
                        >
                        >
                        "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote
                        in message news:%23M7SAaC0 GHA.1568@TK2MSF TNGP03.phx.gbl. ..
                        > That's actually very, very wrong. Something else is going on here.
                        >The temporary variable that is created as a result of calling 2 * c isn't
                        >being GC'ed because the reference is held on the stack (through the
                        >parameter) when you pass it to MyFun.
                        >>
                        > It is most definitely something else. Without seeing the code for the
                        >class where the operator is overloaded, as well as the code for MyFun,
                        >it's impossible to say.
                        >>
                        >>
                        >--
                        > - Nicholas Paldino [.NET/C# MVP]
                        > - mvp@spam.guard. caspershouse.co m
                        >>
                        >"Atmapuri" <dip@community. nospamwrote in message
                        >news:ejuMK1B0G HA.4044@TK2MSFT NGP04.phx.gbl.. .
                        >>Hi!
                        >>>
                        >>I noticed a very funny behaviour when overloading operators
                        >>on objects in C#:
                        >>>
                        >>MyOjbects a,b,c,d;
                        >>...
                        >>//objects are created and initalized here...
                        >>...
                        >>b.Length = 100;
                        >>c.Length = 100;
                        >>>
                        >>for (i = 0; i < 10000; i++)
                        >>{
                        >> a = MyFun(2*c)*b;
                        >>}
                        >>>
                        >>Inside the overladed multiplication operator, I check:
                        >>>
                        >>if (Op1.Length == Op2.Length) throw....
                        >>>
                        >>And the exception triggers after about 100 iterations...!! ?
                        >>Somehow the internal objects of the temporary variable
                        >>created by 2*c passed to MyFun are being
                        >>garbage collected (nullified) before the temporary variable is used for
                        >>the first time...
                        >>>
                        >>Are there some known issues with this?
                        >>>
                        >>Thanks!
                        >>Atmapuri
                        >>>
                        >>
                        >>
                        >
                        >

                        Comment

                        • Atmapuri

                          #13
                          Re: Expressions in C#...

                          Hi!

                          Could it be a problem if I call GC.Collect from inside a
                          class constructor?

                          Thanks!
                          Atmapuri

                          "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c omwrote in
                          message news:%23M7SAaC0 GHA.1568@TK2MSF TNGP03.phx.gbl. ..
                          That's actually very, very wrong. Something else is going on here.
                          The temporary variable that is created as a result of calling 2 * c isn't
                          being GC'ed because the reference is held on the stack (through the
                          parameter) when you pass it to MyFun.
                          >
                          It is most definitely something else. Without seeing the code for the
                          class where the operator is overloaded, as well as the code for MyFun,
                          it's impossible to say.
                          >
                          >
                          --
                          - Nicholas Paldino [.NET/C# MVP]
                          - mvp@spam.guard. caspershouse.co m
                          >
                          "Atmapuri" <dip@community. nospamwrote in message
                          news:ejuMK1B0GH A.4044@TK2MSFTN GP04.phx.gbl...
                          >Hi!
                          >>
                          >I noticed a very funny behaviour when overloading operators
                          >on objects in C#:
                          >>
                          >MyOjbects a,b,c,d;
                          >...
                          >//objects are created and initalized here...
                          >...
                          >b.Length = 100;
                          >c.Length = 100;
                          >>
                          >for (i = 0; i < 10000; i++)
                          >{
                          > a = MyFun(2*c)*b;
                          >}
                          >>
                          >Inside the overladed multiplication operator, I check:
                          >>
                          >if (Op1.Length == Op2.Length) throw....
                          >>
                          >And the exception triggers after about 100 iterations...!! ?
                          >Somehow the internal objects of the temporary variable
                          >created by 2*c passed to MyFun are being
                          >garbage collected (nullified) before the temporary variable is used for
                          >the first time...
                          >>
                          >Are there some known issues with this?
                          >>
                          >Thanks!
                          >Atmapuri
                          >>
                          >
                          >

                          Comment

                          • Marc Gravell

                            #14
                            Re: Expressions in C#...

                            That is a deterministic case.. that will fail in the first loop.

                            My example was for demonstration only, to illustrate what I meant be
                            side-effects.
                            b and c are not modified inside of the loop and also not inside
                            of the operator. That is certain.
                            Well, without the operator code I couldn't (and still can't) see this, but
                            you'll have
                            to excuse me for looking for the straightforward explanations first. A
                            demonstrable
                            example would be the ideal, but I gather that isn't going to happen...

                            Since finalizers are involved, and since we have (seemingly) exhausted the
                            simple
                            options, then it is possible that you are racing the GC; does this article
                            help any?

                            http://blogs.msdn.com/cbrumme/archiv.../19/51365.aspx

                            Marc


                            Comment

                            • Willy Denoyette [MVP]

                              #15
                              Re: Expressions in C#...


                              "Atmapuri" <dip@community. nospamwrote in message
                              news:%23WzWGGD0 GHA.1252@TK2MSF TNGP04.phx.gbl. ..
                              | Hi!
                              |
                              | Could it be a problem if I call GC.Collect from inside a
                              | class constructor?
                              |

                              Please post your code, it makes no sense to ask further questions you only
                              can answer.

                              Willy.


                              Comment

                              Working...