Structs and delegates

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

    Structs and delegates

    Below is a bit of code that creates a delegate.
    The delegate invokes a member function of a struct.
    The code compiles, but has surprising behavior:

    using System;

    namespace ConsoleApplicat ion1
    {
    public struct SimpleStruct
    {
    public int i;

    public void assignToI(int x)
    {
    Console.WriteLi ne("Assigning i: " + x);
    i = x;
    Console.WriteLi ne("i = " + x);
    }
    }

    class Class1
    {
    public delegate void Assigner(int s);

    private static void callDelegate(As signer a, int i)
    {
    a(i);
    }

    static void Main(string[] args)
    {
    SimpleStruct s = new SimpleStruct();
    s.assignToI(1); // Works as expected, assigns 1 to s.i
    System.Console. WriteLine("s.i after calling assignToI = " + s.i);

    // Create a delegate that calls assignToI()
    Assigner assign_to_i = new Assigner(s.assi gnToI);

    // Call helper function, passing delegate and new value for s.i
    callDelegate(as sign_to_i, 99);

    System.Console. WriteLine("s.i after calling delegate = " + s.i);
    // Assignment is lost, s.i still contains 1!!!
    }
    }
    }

    When run, this code prints:

    $ ./ConsoleApplicat ion1.exe
    Assigning i: 1
    i = 1
    s.i after calling assignToI = 1
    Assigning i: 99
    i = 99
    s.i after calling delegate = 1

    Note that the direct call s.assignToI() works as expected:
    after the call, the structure member has new value.

    However, the call via the delagate does not work as expected:
    the value that is assigned is lost, and the structure member
    has the old value.

    Now, I realize what is going on here. The delegate constructor
    expects an argument of type object. In other words, the expression

    new Assigner(s.assi gnToI)

    is internally converted to something like

    new Delegate(s, "assignToI" )

    So, the struct is silently boxed and, when the delegate runs,
    what it assigns to is a temporary copy of the struct on the heap,
    instead of assigning to the real struct.

    Several thoughts here:

    1) I find this surprising. At no point in my code have I passed the
    structure as a parameter, so I don't expect this behavior. (Yes,
    I know that the struct ends up being boxed, but that is not manifest
    anywhere in the code.)

    2) I believe that the behavior is wrong. (Yes, I understand *why* it
    works the way it does, but that doesn't necessarily make the behavior
    right.) Delegates are the equivalent of C++ member function pointers.
    If I create a delegate and pass a method of a struct, I expect the
    delegate to call the method on the struct instance I specified, not
    some temporary copy.

    3) Even if we accept that the behavior is correct, then why does the compiler
    allow me to write this? After all, there is no way that such a delegate would
    ever do something useful, so why not at least emit a warning?

    4) The silent boxing and unboxing in C# seems to be more of a curse than helpful.
    It is too easy to have a value type boxed, only to end up with invocations
    made to a boxed copy on the heap.

    Finally, I'm looking for suggestions as to how I can achieve what the above
    code is trying to do. Basically, what I need to do is assign to a member of
    an already instantiated structure, but without knowing the type of the structure.
    That is, I want to, at least in spirit, be able to assign to a structure member
    via a pointer to the structure.
    (This issue arises in the context of unmarshaling data from the wire and, for
    various legitimate reasons, I have to assign to a member of an already instatiated
    structure, instead of instantiating the structure after I have all its member values.)

    I tried using pointers and unsafe code, but that only works for types that are unmanaged.
    However, the structure may contain managed members, in which case I can no
    longer create a pointer to the struct, so this doesn't work either.

    Any other ideas anyone?

    Thanks,

    Michi.
  • Pete Davis

    #2
    Re: Structs and delegates

    If you make SimpleStruct a class, it will work as expected. The problem is
    that a struct is a value type, not a reference.

    Read more here:


    Pete

    "Michi Henning" <michi@zeroc.co m> wrote in message
    news:OU%23%23mR VyFHA.2644@TK2M SFTNGP09.phx.gb l...[color=blue]
    > Below is a bit of code that creates a delegate.
    > The delegate invokes a member function of a struct.
    > The code compiles, but has surprising behavior:
    >
    > using System;
    >
    > namespace ConsoleApplicat ion1
    > {
    > public struct SimpleStruct
    > {
    > public int i;
    >
    > public void assignToI(int x)
    > {
    > Console.WriteLi ne("Assigning i: " + x);
    > i = x;
    > Console.WriteLi ne("i = " + x);
    > }
    > }
    >
    > class Class1
    > {
    > public delegate void Assigner(int s);
    >
    > private static void callDelegate(As signer a, int i)
    > {
    > a(i);
    > }
    >
    > static void Main(string[] args)
    > {
    > SimpleStruct s = new SimpleStruct();
    > s.assignToI(1); // Works as expected, assigns 1 to s.i
    > System.Console. WriteLine("s.i after calling assignToI = " +
    > s.i);
    >
    > // Create a delegate that calls assignToI()
    > Assigner assign_to_i = new Assigner(s.assi gnToI);
    >
    > // Call helper function, passing delegate and new value for
    > s.i
    > callDelegate(as sign_to_i, 99);
    >
    > System.Console. WriteLine("s.i after calling delegate = " +
    > s.i);
    > // Assignment is lost, s.i still contains 1!!!
    > }
    > }
    > }
    >
    > When run, this code prints:
    >
    > $ ./ConsoleApplicat ion1.exe
    > Assigning i: 1
    > i = 1
    > s.i after calling assignToI = 1
    > Assigning i: 99
    > i = 99
    > s.i after calling delegate = 1
    >
    > Note that the direct call s.assignToI() works as expected:
    > after the call, the structure member has new value.
    >
    > However, the call via the delagate does not work as expected:
    > the value that is assigned is lost, and the structure member
    > has the old value.
    >
    > Now, I realize what is going on here. The delegate constructor
    > expects an argument of type object. In other words, the expression
    >
    > new Assigner(s.assi gnToI)
    >
    > is internally converted to something like
    >
    > new Delegate(s, "assignToI" )
    >
    > So, the struct is silently boxed and, when the delegate runs,
    > what it assigns to is a temporary copy of the struct on the heap,
    > instead of assigning to the real struct.
    >
    > Several thoughts here:
    >
    > 1) I find this surprising. At no point in my code have I passed the
    > structure as a parameter, so I don't expect this behavior. (Yes,
    > I know that the struct ends up being boxed, but that is not manifest
    > anywhere in the code.)
    >
    > 2) I believe that the behavior is wrong. (Yes, I understand *why* it
    > works the way it does, but that doesn't necessarily make the behavior
    > right.) Delegates are the equivalent of C++ member function pointers.
    > If I create a delegate and pass a method of a struct, I expect the
    > delegate to call the method on the struct instance I specified, not
    > some temporary copy.
    >
    > 3) Even if we accept that the behavior is correct, then why does the
    > compiler
    > allow me to write this? After all, there is no way that such a delegate
    > would
    > ever do something useful, so why not at least emit a warning?
    >
    > 4) The silent boxing and unboxing in C# seems to be more of a curse than
    > helpful.
    > It is too easy to have a value type boxed, only to end up with
    > invocations
    > made to a boxed copy on the heap.
    >
    > Finally, I'm looking for suggestions as to how I can achieve what the
    > above
    > code is trying to do. Basically, what I need to do is assign to a member
    > of
    > an already instantiated structure, but without knowing the type of the
    > structure.
    > That is, I want to, at least in spirit, be able to assign to a structure
    > member
    > via a pointer to the structure.
    > (This issue arises in the context of unmarshaling data from the wire and,
    > for
    > various legitimate reasons, I have to assign to a member of an already
    > instatiated
    > structure, instead of instantiating the structure after I have all its
    > member values.)
    >
    > I tried using pointers and unsafe code, but that only works for types that
    > are unmanaged.
    > However, the structure may contain managed members, in which case I can no
    > longer create a pointer to the struct, so this doesn't work either.
    >
    > Any other ideas anyone?
    >
    > Thanks,
    >
    > Michi.[/color]


    Comment

    • Michi Henning

      #3
      Re: Structs and delegates

      Pete Davis wrote:[color=blue]
      > If you make SimpleStruct a class, it will work as expected. The problem is
      > that a struct is a value type, not a reference.[/color]

      Yes, I am aware of that. As I said in my post:
      [color=blue]
      > So, the struct is silently boxed and, when the delegate runs,
      > what it assigns to is a temporary copy of the struct on the heap,
      > instead of assigning to the real struct.
      >
      > [...]
      >
      > 4) The silent boxing and unboxing in C# seems to be more of a curse than
      > helpful. It is too easy to have a value type boxed, only to end up with
      > invocations made to a boxed copy on the heap.[/color]

      My point is that either it shouldn't behave as it does or, if it has to behave
      as it does, the compiler should at least warn me that it's not going to work.

      Michi.

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: Structs and delegates

        Michi Henning <michi@zeroc.co m> wrote:[color=blue]
        > Below is a bit of code that creates a delegate.
        > The delegate invokes a member function of a struct.
        > The code compiles, but has surprising behavior:[/color]

        <snip>
        [color=blue]
        > 3) Even if we accept that the behavior is correct, then why does the compiler
        > allow me to write this? After all, there is no way that such a delegate would
        > ever do something useful, so why not at least emit a warning?[/color]

        What do you expect it to do if the delegate "lives" for longer than the
        current stack frame? What could it possibly operate on then?
        Furthermore, how do you expect the delegate to maintain a reference to
        the struct on the stack in the first place?

        Note that this behaviour is well-defined in the spec - see section
        14.5.10.3 of the ECMA spec.

        --
        Jon Skeet - <skeet@pobox.co m>
        http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
        If replying to the group, please do not mail me too

        Comment

        • Abubakar

          #5
          Re: Structs and delegates

          Hi,
          if I compile your code under Rotor csc, it gives me the following error:
          ---------------------------------------
          Unhandled Exception: System.NotSuppo rtedException: Delegates on value
          classes can only be formed on virtual methods
          at System.Delegate .NeverCallThis( Object target, IntPtr slot)
          at ConsoleApplicat ion1.Class1.Mai n(String[] args)
          ---------------------------------------

          Ab.
          Blogger ist ein Veröffentlichungs-Tool von Google, mit dem du ganz einfach deine Gedanken der Welt mitteilen kannst. Mit Blogger kannst du problemlos Texte, Fotos und Videos in deinem persönlichen Blog oder deinem Team-Blog veröffentlichen.


          "Michi Henning" <michi@zeroc.co m> wrote in message
          news:OU%23%23mR VyFHA.2644@TK2M SFTNGP09.phx.gb l...[color=blue]
          > Below is a bit of code that creates a delegate.
          > The delegate invokes a member function of a struct.
          > The code compiles, but has surprising behavior:
          >
          > using System;
          >
          > namespace ConsoleApplicat ion1
          > {
          > public struct SimpleStruct
          > {
          > public int i;
          >
          > public void assignToI(int x)
          > {
          > Console.WriteLi ne("Assigning i: " + x);
          > i = x;
          > Console.WriteLi ne("i = " + x);
          > }
          > }
          >
          > class Class1
          > {
          > public delegate void Assigner(int s);
          >
          > private static void callDelegate(As signer a, int i)
          > {
          > a(i);
          > }
          >
          > static void Main(string[] args)
          > {
          > SimpleStruct s = new SimpleStruct();
          > s.assignToI(1); // Works as expected, assigns 1 to s.i
          > System.Console. WriteLine("s.i after calling assignToI = " +[/color]
          s.i);[color=blue]
          >
          > // Create a delegate that calls assignToI()
          > Assigner assign_to_i = new Assigner(s.assi gnToI);
          >
          > // Call helper function, passing delegate and new value for[/color]
          s.i[color=blue]
          > callDelegate(as sign_to_i, 99);
          >
          > System.Console. WriteLine("s.i after calling delegate = " +[/color]
          s.i);[color=blue]
          > // Assignment is lost, s.i still contains 1!!!
          > }
          > }
          > }
          >
          > When run, this code prints:
          >
          > $ ./ConsoleApplicat ion1.exe
          > Assigning i: 1
          > i = 1
          > s.i after calling assignToI = 1
          > Assigning i: 99
          > i = 99
          > s.i after calling delegate = 1
          >
          > Note that the direct call s.assignToI() works as expected:
          > after the call, the structure member has new value.
          >
          > However, the call via the delagate does not work as expected:
          > the value that is assigned is lost, and the structure member
          > has the old value.
          >
          > Now, I realize what is going on here. The delegate constructor
          > expects an argument of type object. In other words, the expression
          >
          > new Assigner(s.assi gnToI)
          >
          > is internally converted to something like
          >
          > new Delegate(s, "assignToI" )
          >
          > So, the struct is silently boxed and, when the delegate runs,
          > what it assigns to is a temporary copy of the struct on the heap,
          > instead of assigning to the real struct.
          >
          > Several thoughts here:
          >
          > 1) I find this surprising. At no point in my code have I passed the
          > structure as a parameter, so I don't expect this behavior. (Yes,
          > I know that the struct ends up being boxed, but that is not manifest
          > anywhere in the code.)
          >
          > 2) I believe that the behavior is wrong. (Yes, I understand *why* it
          > works the way it does, but that doesn't necessarily make the behavior
          > right.) Delegates are the equivalent of C++ member function pointers.
          > If I create a delegate and pass a method of a struct, I expect the
          > delegate to call the method on the struct instance I specified, not
          > some temporary copy.
          >
          > 3) Even if we accept that the behavior is correct, then why does the[/color]
          compiler[color=blue]
          > allow me to write this? After all, there is no way that such a[/color]
          delegate would[color=blue]
          > ever do something useful, so why not at least emit a warning?
          >
          > 4) The silent boxing and unboxing in C# seems to be more of a curse than[/color]
          helpful.[color=blue]
          > It is too easy to have a value type boxed, only to end up with[/color]
          invocations[color=blue]
          > made to a boxed copy on the heap.
          >
          > Finally, I'm looking for suggestions as to how I can achieve what the[/color]
          above[color=blue]
          > code is trying to do. Basically, what I need to do is assign to a member[/color]
          of[color=blue]
          > an already instantiated structure, but without knowing the type of the[/color]
          structure.[color=blue]
          > That is, I want to, at least in spirit, be able to assign to a structure[/color]
          member[color=blue]
          > via a pointer to the structure.
          > (This issue arises in the context of unmarshaling data from the wire and,[/color]
          for[color=blue]
          > various legitimate reasons, I have to assign to a member of an already[/color]
          instatiated[color=blue]
          > structure, instead of instantiating the structure after I have all its[/color]
          member values.)[color=blue]
          >
          > I tried using pointers and unsafe code, but that only works for types that[/color]
          are unmanaged.[color=blue]
          > However, the structure may contain managed members, in which case I can no
          > longer create a pointer to the struct, so this doesn't work either.
          >
          > Any other ideas anyone?
          >
          > Thanks,
          >
          > Michi.[/color]


          Comment

          • Abubakar

            #6
            Re: Structs and delegates

            I meant compile AND run.

            Ab.


            "Abubakar" <abubakarm@gmai l.com> wrote in message
            news:eROPUKYyFH A.612@TK2MSFTNG P10.phx.gbl...[color=blue]
            > Hi,
            > if I compile your code under Rotor csc, it gives me the following error:
            > ---------------------------------------
            > Unhandled Exception: System.NotSuppo rtedException: Delegates on value
            > classes can only be formed on virtual methods
            > at System.Delegate .NeverCallThis( Object target, IntPtr slot)
            > at ConsoleApplicat ion1.Class1.Mai n(String[] args)
            > ---------------------------------------
            >
            > Ab.
            > http://joehacker.blogspot.com
            >
            > "Michi Henning" <michi@zeroc.co m> wrote in message
            > news:OU%23%23mR VyFHA.2644@TK2M SFTNGP09.phx.gb l...[color=green]
            > > Below is a bit of code that creates a delegate.
            > > The delegate invokes a member function of a struct.
            > > The code compiles, but has surprising behavior:
            > >
            > > using System;
            > >
            > > namespace ConsoleApplicat ion1
            > > {
            > > public struct SimpleStruct
            > > {
            > > public int i;
            > >
            > > public void assignToI(int x)
            > > {
            > > Console.WriteLi ne("Assigning i: " + x);
            > > i = x;
            > > Console.WriteLi ne("i = " + x);
            > > }
            > > }
            > >
            > > class Class1
            > > {
            > > public delegate void Assigner(int s);
            > >
            > > private static void callDelegate(As signer a, int i)
            > > {
            > > a(i);
            > > }
            > >
            > > static void Main(string[] args)
            > > {
            > > SimpleStruct s = new SimpleStruct();
            > > s.assignToI(1); // Works as expected, assigns 1 to s.i
            > > System.Console. WriteLine("s.i after calling assignToI = " +[/color]
            > s.i);[color=green]
            > >
            > > // Create a delegate that calls assignToI()
            > > Assigner assign_to_i = new Assigner(s.assi gnToI);
            > >
            > > // Call helper function, passing delegate and new value for[/color]
            > s.i[color=green]
            > > callDelegate(as sign_to_i, 99);
            > >
            > > System.Console. WriteLine("s.i after calling delegate = " +[/color]
            > s.i);[color=green]
            > > // Assignment is lost, s.i still contains 1!!!
            > > }
            > > }
            > > }
            > >
            > > When run, this code prints:
            > >
            > > $ ./ConsoleApplicat ion1.exe
            > > Assigning i: 1
            > > i = 1
            > > s.i after calling assignToI = 1
            > > Assigning i: 99
            > > i = 99
            > > s.i after calling delegate = 1
            > >
            > > Note that the direct call s.assignToI() works as expected:
            > > after the call, the structure member has new value.
            > >
            > > However, the call via the delagate does not work as expected:
            > > the value that is assigned is lost, and the structure member
            > > has the old value.
            > >
            > > Now, I realize what is going on here. The delegate constructor
            > > expects an argument of type object. In other words, the expression
            > >
            > > new Assigner(s.assi gnToI)
            > >
            > > is internally converted to something like
            > >
            > > new Delegate(s, "assignToI" )
            > >
            > > So, the struct is silently boxed and, when the delegate runs,
            > > what it assigns to is a temporary copy of the struct on the heap,
            > > instead of assigning to the real struct.
            > >
            > > Several thoughts here:
            > >
            > > 1) I find this surprising. At no point in my code have I passed the
            > > structure as a parameter, so I don't expect this behavior. (Yes,
            > > I know that the struct ends up being boxed, but that is not manifest
            > > anywhere in the code.)
            > >
            > > 2) I believe that the behavior is wrong. (Yes, I understand *why* it
            > > works the way it does, but that doesn't necessarily make the[/color][/color]
            behavior[color=blue][color=green]
            > > right.) Delegates are the equivalent of C++ member function[/color][/color]
            pointers.[color=blue][color=green]
            > > If I create a delegate and pass a method of a struct, I expect the
            > > delegate to call the method on the struct instance I specified, not
            > > some temporary copy.
            > >
            > > 3) Even if we accept that the behavior is correct, then why does the[/color]
            > compiler[color=green]
            > > allow me to write this? After all, there is no way that such a[/color]
            > delegate would[color=green]
            > > ever do something useful, so why not at least emit a warning?
            > >
            > > 4) The silent boxing and unboxing in C# seems to be more of a curse than[/color]
            > helpful.[color=green]
            > > It is too easy to have a value type boxed, only to end up with[/color]
            > invocations[color=green]
            > > made to a boxed copy on the heap.
            > >
            > > Finally, I'm looking for suggestions as to how I can achieve what the[/color]
            > above[color=green]
            > > code is trying to do. Basically, what I need to do is assign to a member[/color]
            > of[color=green]
            > > an already instantiated structure, but without knowing the type of the[/color]
            > structure.[color=green]
            > > That is, I want to, at least in spirit, be able to assign to a structure[/color]
            > member[color=green]
            > > via a pointer to the structure.
            > > (This issue arises in the context of unmarshaling data from the wire[/color][/color]
            and,[color=blue]
            > for[color=green]
            > > various legitimate reasons, I have to assign to a member of an already[/color]
            > instatiated[color=green]
            > > structure, instead of instantiating the structure after I have all its[/color]
            > member values.)[color=green]
            > >
            > > I tried using pointers and unsafe code, but that only works for types[/color][/color]
            that[color=blue]
            > are unmanaged.[color=green]
            > > However, the structure may contain managed members, in which case I can[/color][/color]
            no[color=blue][color=green]
            > > longer create a pointer to the struct, so this doesn't work either.
            > >
            > > Any other ideas anyone?
            > >
            > > Thanks,
            > >
            > > Michi.[/color]
            >
            >[/color]


            Comment

            • Bruce Wood

              #7
              Re: Structs and delegates

              The difficulty, as I see it, is that you are using a screwdriver to
              pound a nail into a wall.

              Why do you have a mutable structure in the first place? Yes, I know
              that Microsoft did it with Point, Rectangle, etc. (for specific
              performance reasons), but that doesn't make it generally good practice,
              because you end up with precisely the kinds of problems you're
              outlining here.

              I've built many structs, but they're all immutable, so they act just
              like values, like int, double, etc., so I never run across these
              problems.

              Should it be easier to modify a struct field using something like a C++
              method pointer? That sounds to me like the assertion that it really
              should be easier to use a screwdriver as a hammer, and there's
              something wrong with screwdrivers that doesn't permit them to be easily
              used in that way.

              I side with Pete Davis: What design problem caused you to choose a
              struct over a class here?

              Comment

              • Michi Henning

                #8
                Re: Structs and delegates

                Jon Skeet [C# MVP] wrote:
                [color=blue]
                >
                >
                > What do you expect it to do if the delegate "lives" for longer than the
                > current stack frame? What could it possibly operate on then?[/color]

                When the delegate tries to call the struct member function, it could
                throw an exception if the struct is no longer there.
                [color=blue]
                > Furthermore, how do you expect the delegate to maintain a reference to
                > the struct on the stack in the first place?[/color]

                Well, that would be the job of the compiler.
                [color=blue]
                > Note that this behaviour is well-defined in the spec - see section
                > 14.5.10.3 of the ECMA spec.[/color]

                Right. No argument there. The behavior is exactly as prescribed by
                the spec. That doesn't make it any more useful though ;-)

                I honestly can't think of why I would want to deliberately do this--
                having a delegate call into a temporary anonymous copy of a value
                type would never achieve anything useful, as far as I can see.
                It would be nice if the compiler emitted a warning for this case.

                Cheers,

                Michi.

                Comment

                • Michi Henning

                  #9
                  Re: Structs and delegates

                  Bruce Wood wrote:[color=blue]
                  >
                  > Why do you have a mutable structure in the first place? Yes, I know
                  > that Microsoft did it with Point, Rectangle, etc. (for specific
                  > performance reasons), but that doesn't make it generally good practice,
                  > because you end up with precisely the kinds of problems you're
                  > outlining here.
                  >
                  > [...]
                  >
                  > Should it be easier to modify a struct field using something like a C++
                  > method pointer? That sounds to me like the assertion that it really
                  > should be easier to use a screwdriver as a hammer, and there's
                  > something wrong with screwdrivers that doesn't permit them to be easily
                  > used in that way.
                  >
                  > I side with Pete Davis: What design problem caused you to choose a
                  > struct over a class here?[/color]

                  The whole story is quite complex. It arises in the context of
                  unmarshaling data for the Ice middleware. If you want to know
                  all the details, check out the Slice chapter and the Protocol
                  chapter in the Ice documentation (http://www.zeroc.com/Ice-Manual.pdf).
                  Read up on structs and classes.

                  Basically, a Slice struct maps to a C# struct by default. Slice
                  structs can contain class members, which map to C# references.
                  And classes can form circular graphs. To unmarshal cycles of classes,
                  it is necessary to break the cycle somewhere. In turn, that means
                  that I must unmarshal a class instance before all the values of
                  its data members have been unmarshaled. The way the unmarshaling
                  code deals with this is to unmarshal the class instance and then
                  later, when an instance arrives that is referred to by a member of
                  the first instance, the code patches the corresponding member in
                  the first instance by assigning to it.

                  This isn't a problem for classes, because they are reference types,
                  but it is a problem for structures, which aren't.

                  The language mapping maps Slice structs to C# structs for efficiency
                  reasons--it's faster to instantiate a struct than to instantiate a
                  class.


                  Cheers,

                  Michi.

                  Comment

                  • Michi Henning

                    #10
                    Re: Structs and delegates

                    Abubakar wrote:[color=blue]
                    > Hi,
                    > if I compile your code under Rotor csc, it gives me the following error:
                    > ---------------------------------------
                    > Unhandled Exception: System.NotSuppo rtedException: Delegates on value
                    > classes can only be formed on virtual methods
                    > at System.Delegate .NeverCallThis( Object target, IntPtr slot)
                    > at ConsoleApplicat ion1.Class1.Mai n(String[] args)
                    > ---------------------------------------[/color]

                    Interesting! I don't have Rotor csc. Does the error go away
                    if you make assignToI() a virtual method?

                    Cheers,

                    Michi.

                    Comment

                    • Willy Denoyette [MVP]

                      #11
                      Re: Structs and delegates

                      Inline

                      Willy.

                      "Michi Henning" <michi@zeroc.co m> wrote in message
                      news:%23%23l2wV fyFHA.596@TK2MS FTNGP12.phx.gbl ...[color=blue]
                      > Jon Skeet [C# MVP] wrote:
                      >[color=green]
                      >>
                      >>
                      >> What do you expect it to do if the delegate "lives" for longer than the
                      >> current stack frame? What could it possibly operate on then?[/color]
                      >
                      > When the delegate tries to call the struct member function, it could
                      > throw an exception if the struct is no longer there.
                      >[/color]

                      Why? this call is perfectly valid, the method is not called on the value
                      type, it's called on a boxed copy, and the new value of the member i is set
                      on the boxed type (in your sample i which is 1 is set to 99), not on the
                      value type (on the callers stack). When you return from the delegate, the
                      boxed type is no longer referenced and will be collected when the GC comes
                      along.

                      [color=blue][color=green]
                      >> Furthermore, how do you expect the delegate to maintain a reference to
                      >> the struct on the stack in the first place?[/color]
                      >
                      > Well, that would be the job of the compiler.
                      >[/color]

                      The reference on the stack is maintained, no problem.
                      [color=blue][color=green]
                      >> Note that this behaviour is well-defined in the spec - see section
                      >> 14.5.10.3 of the ECMA spec.[/color]
                      >
                      > Right. No argument there. The behavior is exactly as prescribed by
                      > the spec. That doesn't make it any more useful though ;-)
                      >
                      > I honestly can't think of why I would want to deliberately do this--
                      > having a delegate call into a temporary anonymous copy of a value
                      > type would never achieve anything useful, as far as I can see.
                      > It would be nice if the compiler emitted a warning for this case.
                      >
                      > Cheers,
                      >
                      > Michi.[/color]


                      Comment

                      • Bruce Wood

                        #12
                        Re: Structs and delegates

                        Thanks for the excellent explanation.

                        Comment

                        • Abubakar

                          #13
                          Re: Structs and delegates

                          Hi, no the error doesnt go away. I had to make a lil change to the rotor
                          source to make it work. After discussing with few people I came to know that
                          this was a restriction only in v1 of the .net framework. In v1.1 and onwards
                          it was fixed. After my fix the output was ditto as it in C# 2.0 beta 2.

                          Ab.
                          http://joehacker.blogspot.com.


                          "Michi Henning" <michi@zeroc.co m> wrote in message
                          news:%23fumLefy FHA.1028@TK2MSF TNGP12.phx.gbl. ..[color=blue]
                          > Abubakar wrote:[color=green]
                          > > Hi,
                          > > if I compile your code under Rotor csc, it gives me the following error:
                          > > ---------------------------------------
                          > > Unhandled Exception: System.NotSuppo rtedException: Delegates on value
                          > > classes can only be formed on virtual methods
                          > > at System.Delegate .NeverCallThis( Object target, IntPtr slot)
                          > > at ConsoleApplicat ion1.Class1.Mai n(String[] args)
                          > > ---------------------------------------[/color]
                          >
                          > Interesting! I don't have Rotor csc. Does the error go away
                          > if you make assignToI() a virtual method?
                          >
                          > Cheers,
                          >
                          > Michi.[/color]


                          Comment

                          • Abubakar

                            #14
                            Re: Structs and delegates

                            btw, have u been able to workaround this issue yet?

                            Ab.

                            "Michi Henning" <michi@zeroc.co m> wrote in message
                            news:%23fumLefy FHA.1028@TK2MSF TNGP12.phx.gbl. ..[color=blue]
                            > Abubakar wrote:[color=green]
                            > > Hi,
                            > > if I compile your code under Rotor csc, it gives me the following error:
                            > > ---------------------------------------
                            > > Unhandled Exception: System.NotSuppo rtedException: Delegates on value
                            > > classes can only be formed on virtual methods
                            > > at System.Delegate .NeverCallThis( Object target, IntPtr slot)
                            > > at ConsoleApplicat ion1.Class1.Mai n(String[] args)
                            > > ---------------------------------------[/color]
                            >
                            > Interesting! I don't have Rotor csc. Does the error go away
                            > if you make assignToI() a virtual method?
                            >
                            > Cheers,
                            >
                            > Michi.[/color]


                            Comment

                            • Jon Skeet [C# MVP]

                              #15
                              Re: Structs and delegates

                              Michi Henning <michi@zeroc.co m> wrote:[color=blue][color=green]
                              > > What do you expect it to do if the delegate "lives" for longer than the
                              > > current stack frame? What could it possibly operate on then?[/color]
                              >
                              > When the delegate tries to call the struct member function, it could
                              > throw an exception if the struct is no longer there.[/color]

                              That sounds like a fairly complicated way of doing things, and just as
                              unsatisfactory as the current behaviour IMO.
                              [color=blue][color=green]
                              > > Furthermore, how do you expect the delegate to maintain a reference to
                              > > the struct on the stack in the first place?[/color]
                              >
                              > Well, that would be the job of the compiler.
                              >[color=green]
                              > > Note that this behaviour is well-defined in the spec - see section
                              > > 14.5.10.3 of the ECMA spec.[/color]
                              >
                              > Right. No argument there. The behavior is exactly as prescribed by
                              > the spec. That doesn't make it any more useful though ;-)
                              >
                              > I honestly can't think of why I would want to deliberately do this--
                              > having a delegate call into a temporary anonymous copy of a value
                              > type would never achieve anything useful, as far as I can see.
                              > It would be nice if the compiler emitted a warning for this case.[/color]

                              It only wouldn't achieve anything useful if you wanted to change the
                              values, and as structs should almost always be immutable, it's very
                              rarely a problem.

                              --
                              Jon Skeet - <skeet@pobox.co m>
                              http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
                              If replying to the group, please do not mail me too

                              Comment

                              Working...