Using as operator on value tye array

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

    Using as operator on value tye array

    Dear All
    I have a small problem with using as operator on value type array.

    Here is an example what I am trying to do.

    using System;

    using System.Collecti ons.Generic;

    using System.Text;



    namespace TestDynamicCast

    {

    class Program

    {

    static void Main(string[] args)

    {

    uint[] array1 = { uint.MaxValue - 1, uint.MaxValue - 2 };

    MyMethod(array1 );

    }



    public static void MyMethod(Array arr)

    {

    int[] afterCast1 = arr as int[];

    if (null != afterCast1) //cast is successfull. Is it correct?

    {

    //DoSomeThing

    }

    else

    {

    float[] afterCast2 = arr as float[];

    if (null != afterCast2) //cast fails which is OK

    {

    //DoSomeThingElse

    }

    }

    }

    }

    }



    I think first 'if' condition itself must fail because int[] and uint[] are
    not same, but it's able cast it successfully.



    Please let me know what's going wrong with my code and how to solve this
    problem


    Thanks in advance.

    _______________ _______________ _______________ _______________ _______________ __
    Krishna Rao K
    Lucid Software Ltd 104, NSIC STP Complex | Guindy Industrial Estate |
    Ekkattuthangal | Chennai 600032 ' +91 44 2225 2273 / 76 , +91 98407 28998
    _______________ _______________ _______________ ___________


  • Peter Duniho

    #2
    Re: Using as operator on value tye array

    On Tue, 10 Jun 2008 22:55:10 -0700, Jon Skeet [C# MVP] <skeet@pobox.co m>
    wrote:
    [...]
    >Please let me know what's going wrong with my code and how to solve this
    >problem
    >
    Basically C# itself doesn't believe the conversion is valid, but the
    CLR is happy to do it.
    I'm glad you've explained it (however briefly :) ). I just spent a fair
    amount of time trying to integrate all of the different parts of the C#
    spec that seem to address this, and all I could come up with was that it
    shouldn't work.

    I am curious though: by what rule is the CLR allowed to override the C#
    specification? Or, put another way, given that the CLR doesn't check this
    itself, why isn't the C# compiler emitting the appropriate code to deal
    with the situation?

    If the C# spec had just left it as a general language semantics issue, I
    could maybe see the current behavior. But the spec specifically says:

    For an explicit reference conversion to succeed at run-time,
    the value of the source operand must be null, or the _actual_
    type of the object referenced by the source operand must be
    a type that can be converted to the destination type by an
    implicit reference conversion.

    In this case, there is no implicit reference conversion that could convert
    the actual type (uint[]) to the destination type (int[]). If the C# spec
    is making statements regarding the _run-time_ behavior, it seems to me
    that when the run-time doesn't guarantee the behavior, the compiler needs
    to.

    I realize this is sort of an esoteric question, but I'm wondering if you
    have any insight as to whether this is actually being considered a bug by
    someone who matters (as opposed to me or the OP...I know _I_ think it's a
    bug), or is this something that a C# compiler person would claim is
    working as intended?

    Pete

    Comment

    • Jon Skeet [C# MVP]

      #3
      Re: Using as operator on value tye array

      On Jun 11, 7:19 am, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
      wrote:
      Basically C# itself doesn't believe the conversion is valid, but the
      CLR is happy to do it.
      >
      I'm glad you've explained it (however briefly :) ). I just spent a fair
      amount of time trying to integrate all of the different parts of the C#
      spec that seem to address this, and all I could come up with was that it
      shouldn't work.
      And indeed it doesn't if you try to go straight from int[] to uint[] -
      the compiler won't let you. You have to go via Array, or Object, or
      something like that.
      I am curious though: by what rule is the CLR allowed to override the C#
      specification? Or, put another way, given that the CLR doesn't check this
      itself, why isn't the C# compiler emitting the appropriate code to deal
      with the situation?
      In short, the C# and CLR specs aren't quite aligned on every aspect of
      conversion. This is certainly unfortunate, but was likely to be the
      case at some point.
      If the C# spec had just left it as a general language semantics issue, I
      could maybe see the current behavior. But the spec specifically says:
      >
      For an explicit reference conversion to succeed at run-time,
      the value of the source operand must be null, or the _actual_
      type of the object referenced by the source operand must be
      a type that can be converted to the destination type by an
      implicit reference conversion.
      >
      In this case, there is no implicit reference conversion that could convert
      the actual type (uint[]) to the destination type (int[]). If the C# spec
      is making statements regarding the _run-time_ behavior, it seems to me
      that when the run-time doesn't guarantee the behavior, the compiler needs
      to.
      Right. I think in this case the spec should explicitly call out that
      the runtime is free to make more things valid. Otherwise it's being
      *very* prescriptive of the runtime.
      I realize this is sort of an esoteric question, but I'm wondering if you
      have any insight as to whether this is actually being considered a bug by
      someone who matters (as opposed to me or the OP...I know _I_ think it's a
      bug), or is this something that a C# compiler person would claim is
      working as intended?
      I haven't actually checked the CLI spec, but I'd certainly imagine
      it's allowed there. I suspect it would be deemed "working as expected,
      but unfortunately misleading in the spec". I'll raise it with the C#
      team and see what they say. I would personally like it to stay as it
      is - if the compiler generated extra checks around every conversion,
      it would be painfully slow, just to make things fail in very
      occasional situations. I'd much prefer the spec to have a caveat that
      the conversion is guaranteed to succeed in situation X, but *may* also
      succeed in other situations.

      Jon

      Comment

      • Duggi

        #4
        Re: Using as operator on value tye array

        Hi KK,

        I am sure you are running the code in unchecked mode otherwise the
        statement

        uint[] array = { uint.MinValue - 1, uint.MaxValue - 2 };

        would have given you some compile error.

        However that is not the cause for the issue you are facing.
        There are two casting operations that this code does. First casting is
        done when the uint[] is passed to method to Array. Second cast to
        Array to int[], both are perfectly valid and so does the code.

        If you want the first condition to be failed, try passing the unit[]
        as uint[] itself.

        public static void MyMethod(unit[] arr)
        {
        int[] afterCast1 = arr as
        int[]; // This is an error.
        if (null != afterCast1) //cast is successfull. Is it correct?
        {
        //DoSomeThing
        }
        }

        Now you will hit by an error.

        I hope this will help you!!!

        -Cnu

        Comment

        • Peter Duniho

          #5
          Re: Using as operator on value tye array

          On Tue, 10 Jun 2008 23:33:59 -0700, Jon Skeet [C# MVP] <skeet@pobox.co m>
          wrote:
          [...] I'd much prefer the spec to have a caveat that
          the conversion is guaranteed to succeed in situation X, but *may* also
          succeed in other situations.
          Sure, that'd be fine with me too. My complaint is with the apparent
          disconnect between the statements in the spec and the actual behavior.

          If the fix is simply to edit the spec, I don't have an issue with that.
          It's just that the way the spec is worded now, it seems to very clearly
          say that not only is this not an acceptable conversion in C#, it shouldn't
          work at run-time either. I don't mind if someone decides to change the
          spec, justifying the change on the thought that the C# spec probably
          doesn't have the authority over the run-time that it seems to think it
          has. :)

          (Though, granted, the spec certainly does assume certain features that are
          required to be in the CLR. But I think those are more of a "C# needs this
          to work", than the current issue, which is more of a "C# wants this not to
          work", so I don't really consider them the same sort of thing).

          Pete

          Comment

          • kodehoved

            #6
            Re: Using as operator on value tye array

            I spend some time going through the language spec as well without
            finding a clear answer to this.

            Jon, could you elaborate a bit on why exactly this conversion is
            allowed?

            As far as I can tell this only works from "unsigned type[]" to
            "type[]" (e.g. uint[] to int[]). Swapping uint[] for any other integer
            array type makes the cast fail. However, you can do the same with e.g.
            ulong[] to long[] and so forth.

            Thanks,
            Brian

            Comment

            • Jon Skeet [C# MVP]

              #7
              Re: Using as operator on value tye array

              <snip>

              Copying part of the reply I sent by email - in future, please keep
              discussions to *either* the newsgroup *or* email, *or* state on the
              message that it's going to both. If I get an email before I see the
              group response, I'll normally reply to that - which then means I
              either have to copy the response to the group or leave it unanswered
              on the group.

              Anyway, back to your post:
              Coming to the problem, when the cast fails when source in an unit array and
              trying to cast to float array, why can't CLR perform
              the same check against int & uint arrays? And strangely after the cast in my
              previous code, the values displayed in the debugger
              are still unit values and afterCast1.GetT ype() is still returning
              'System.Int32[]'? This is what is confusing.
              The array still *is* an int[] at its heart, but the CLR is able to
              treat signed and unsigned integers basically as the same thing. You'll
              see short[] and ushort[] behave the same way. I've now tried to find
              the relevant bit of the CLI spec, but can't. I'll ask the teams
              involved.
              The same problem exists in C++/CLI, that means is it bug with CLR?
              Well, it means it's the CLR doing it. Whether or not it's a bug is a
              different matter - I suspect the CLI spec just allows it somewhere, in
              which case it's a mismatch between language expectations and CLI
              expectations.

              Interesting stuff though...

              Jon

              Comment

              • Jon Skeet [C# MVP]

                #8
                Re: Using as operator on value tye array

                Peter Duniho <NpOeStPeAdM@nn owslpianmk.comw rote:
                [...] I'd much prefer the spec to have a caveat that
                the conversion is guaranteed to succeed in situation X, but *may* also
                succeed in other situations.
                >
                Sure, that'd be fine with me too. My complaint is with the apparent
                disconnect between the statements in the spec and the actual behavior.
                Absolutely.
                If the fix is simply to edit the spec, I don't have an issue with that.
                It's just that the way the spec is worded now, it seems to very clearly
                say that not only is this not an acceptable conversion in C#, it shouldn't
                work at run-time either. I don't mind if someone decides to change the
                spec, justifying the change on the thought that the C# spec probably
                doesn't have the authority over the run-time that it seems to think it
                has. :)
                Okay, I'll mail appropriate and post back with whatever I find :)
                (Though, granted, the spec certainly does assume certain features that are
                required to be in the CLR. But I think those are more of a "C# needs this
                to work", than the current issue, which is more of a "C# wants this not to
                work", so I don't really consider them the same sort of thing).
                Exactly. Positive requirements are more understandable than negative
                ones.

                On the other hand, I *would* want the runtime to fail to convert, say,
                a bare System.Object to a System.String by picking the empty string. I
                think C# should be able to assume that won't happen - in which case,
                where do you draw the line? Sooner or later it's going to be a
                pragmatic decision...

                --
                Jon Skeet - <skeet@pobox.co m>
                Web site: http://www.pobox.com/~skeet
                Blog: http://www.msmvps.com/jon.skeet
                C# in Depth: http://csharpindepth.com

                Comment

                • Jon Skeet [C# MVP]

                  #9
                  Re: Using as operator on value tye array

                  kodehoved <afkatm@gmail.c omwrote:
                  I spend some time going through the language spec as well without
                  finding a clear answer to this.
                  >
                  Jon, could you elaborate a bit on why exactly this conversion is
                  allowed?
                  Will do when I've heard back from CLR folks :)
                  As far as I can tell this only works from "unsigned type[]" to
                  "type[]" (e.g. uint[] to int[]). Swapping uint[] for any other integer
                  array type makes the cast fail. However, you can do the same with e.g.
                  ulong[] to long[] and so forth.
                  It would also happen for something like:

                  enum Foo : short {}

                  Foo[] x = new Foo[10];
                  Array y = x;
                  short[] z = (short[]) y;

                  --
                  Jon Skeet - <skeet@pobox.co m>
                  Web site: http://www.pobox.com/~skeet
                  Blog: http://www.msmvps.com/jon.skeet
                  C# in Depth: http://csharpindepth.com

                  Comment

                  • Jon Skeet [C# MVP]

                    #10
                    Re: Using as operator on value tye array

                    Jon Skeet [C# MVP] <skeet@pobox.co mwrote:
                    Okay, I'll mail appropriate and post back with whatever I find :)
                    <snip>

                    Right - Eric Lippert has replied. It's probably worth reproducing the
                    question as I asked it, to make the reply make more sense. Be warned,
                    it's a long and detailed answer - just the kind I like :)

                    Question:
                    I've been aware of a few differences between what the C# spec claims is
                    allowed and what the CLR allows when it comes to conversions. However,
                    I think this is a new one on me:

                    using System;

                    class Test
                    {
                    static void Main(string[] args)
                    {
                    Array ints = new int[] {1, 2, 3};
                    uint[] uints = (uint[]) ints;

                    Console.WriteLi ne(uints.GetTyp e());
                    }
                    }

                    This runs with no exceptions, and produces the following output:
                    System.Int32[]

                    (Interestingly, if you box an element of "uints" that *does* get boxed
                    as a uint, because it's the compiler which specifies the type there.)

                    The relevant bits are the C# spec is 6.2.4:

                    <quote>For an explicit reference conversion to succeed at run-time, the
                    value of the source operand must be null, or the actual type of the
                    object referenced by the source operand must be a type that can be
                    converted to the destination type by an implicit reference conversion
                    (§6.1.6). If an explicit reference conversion fails, a
                    System.InvalidC astException is thrown.
                    </quote>

                    Now, there's no implicit reference conversion from int[] to uint[], so
                    already the spec has been violated. However, I'd expected to see why
                    the CLR allowed this in ECMA-335 - so we move on to partition 3, 4.3,
                    the castclass instruction (as emitted by the C# compiler):

                    <quote>
                    Note that:
                    1. Arrays inherit from System.Array.
                    2. If Foo can be cast to Bar, then Foo[] can be cast to Bar[].
                    3. For the purposes of note 2 above, enums are treated as their
                    underlying type: thus E1[] can be cast
                    to E2[] if E1 and E2 share an underlying type.
                    </quote>

                    Now, this would see to make a certain amount of sense, if we deem that
                    "int can be cast to uint" - except that I'm not sure of the use of the
                    word "cast" here. It certainly doesn't work for everything: you can
                    cast an int to a float, or a long, or a byte - but you can't convert
                    int[] to float[], long[] or byte[].


                    So, to sum up:
                    1) Assuming the C# spec wants to leave a little wiggle room for the
                    CLR, I don't think it should be quite so prescriptive - it would be
                    worth mentioning that the runtime may make some extra conversions
                    available. It's a bit of a shame to have areas of uncertainty like this
                    (we certainly wouldn't want the CLR to start converting completely
                    unrelated types, for instance) but I understand there's a small matter
                    of pragmatism.

                    2) It looks to me like either ECMA-335 is poorly worded, and/or the CLR
                    is violating it.

                    Anyone care to enlighten me?


                    ------------------- End of question ---------------------

                    Eric's response:

                    Jon=3Fs analysis is pretty much correct; there are conversions which the
                    CLR allows which C# does not. Because of that, if you hammer on it hard
                    enough, you can make a C# program which you would think ought to throw
                    an invalid cast exception, but in fact succeeds.


                    However, though I hate to be contradictory, I must point out that this
                    is not correct.

                    you can cast an int to a float, or a long, or a byte

                    It is not legal to issue a castclass instruction from int to float.
                    Remember, you are talking about the CLR definition of =3Fcast=3F here, not
                    the C# definition, so do not confuse the two.

                    The confusion is our fault, in two ways.

                    First source of confusion: in C# we have conflated two completely
                    different operations as =3Fcast=3F operations. The two operations that we
                    have conflated are what the CLR calls casts and coercions.

                    8.3.2 Coercion

                    Sometimes it is desirable to take a value of a type that is not
                    assignment-compatible with a location, and convert the value to a
                    type that is assignment-compatible. This is accomplished through
                    coercion of the value.

                    Coercion takes a value of a particular type and a desired type and
                    attempts to create a value of the desired type that has equivalent
                    meaning to the original value. Coercion can result in
                    representation changes as well as type changes; hence coercion does
                    not necessarily preserve the identity of two objects.

                    There are two kinds of coercion: widening, which never loses
                    information, and narrowing, in which information might be lost. An
                    example of a widening coercion would be coercing a value that is a
                    32-bit signed integer to a value that is a 64-bit signed integer.
                    An example of a narrowing coercion is the reverse: coercing a 64-
                    bit signed integer to a 32-bit signed integer. Programming
                    languages often implement widening coercions as implicit
                    conversions, whereas narrowing coercions usually require an
                    explicit conversion.

                    Some widening coercion is built directly into the VES operations on
                    the built-in types (see §12.1). All other coercion shall be
                    explicitly requested. For the built-in types, the CTS provides
                    operations to perform widening coercions with no runtime checks and
                    narrowing coercions with runtime checks.

                    8.3.3 Casting

                    Since a value can be of more than one type, a use of the value
                    needs to clearly identify which of its types is being used. Since
                    values are read from locations that are typed, the type of the
                    value which is used is the type of the location from which the
                    value was read. If a different type is to be used, the value is
                    cast to one of its other types. Casting is usually a compile time
                    operation, but if the compiler cannot statically know that the
                    value is of the target type, a runtime cast check is done. Unlike
                    coercion, a cast never changes the actual type of an object nor
                    does it change the representation. Casting preserves the identity
                    of objects.

                    For example, a runtime check might be needed when casting a value
                    read from a location that is typed as holding a value of a
                    particular interface. Since an interface is an incomplete
                    description of the value, casting that value to be of a different
                    interface type will usually result in a runtime cast check.

                    We conflate these two things in C#, using the same operator syntax and
                    terminology for both casts and coercions.

                    So now it should be clear that there is no =3Fcast=3F from int to floatin
                    the CLR. That=3Fs a coercion, not a cast.


                    Second source of confusion: inconsistency in the CLR spec.


                    The CLR spec says in section 8.7


                    Signed and unsigned integral primitive types can be assigned to
                    each other; e.g., int8 := uint8 is valid. For this purpose, bool
                    shall be considered compatible with uint8 and vice versa, which
                    makes bool := uint8 valid, and vice versa. This is also true for
                    arrays of signed and unsigned integral primitive types of the same
                    size; e.g., int32[] := uint32[] is valid.

                    And in section 4.3:

                    If the class of the object on the top of the stack does not
                    implement class (if class is an interface), and is not a derived
                    class of class (if class is a regular class), then an
                    InvalidCastExce ption is thrown.

                    =3F

                    2. If Foo can be cast to Bar, then Foo[] can be cast to Bar[].


                    Where does the spec for castclass say that int32[] can be cast to
                    uint32[]? It doesn=3Ft. It should! int32 and uint32 are assignment
                    compatible, so they can be cast from one to the other without changing
                    bits. But they do not implement or derive from each other, so a strict
                    reading of the spec says that this cast should fail, and therefore
                    int32[] to uint32[] should also fail.


                    Clearly that is not what was meant and not what was implemented.
                    Casting between assignment-compatible types should be legal. Really
                    what this should say is something like =3FIf Foo can be cast to Bar or
                    Foo is assignment compatible with Bar then Foo[] can be cast to Bar[]=3F


                    Fortunately, the CLR guys did NOT extend this goofy kind of type
                    variance to covariant and contravariant interfaces, which as you know
                    we are probably adding in a future version of C#. That is, if we make
                    IEnumerable<Tco variant in T, it will NOT be possible to do a clever
                    series of casts to trick the CLR into assigning an IEnumerable<int to
                    an IEnumerable<uin t>, even though it is possible to make int[] go to
                    uint[]. However, I think it is possible =3F I haven=3Ft checked this yet =3F
                    to leverage the fact that int[] goes to uint[] to similarly force
                    IEnumerable<int[]to go to IEnumerable<uin t[]>.


                    This situation =3F the CLR being more generous about what identity-
                    preserving casts are legal =3F may end up considerably complicating my
                    life in other ways involving covariance and contravariance as we
                    attempt to detect ambiguous conversions at compile time, but that=3Fs
                    another story and we are still researching it.

                    ------------------- End of answer ---------------------

                    I'd just like to thank Eric for posting such a complete and
                    illuminating answer.

                    --
                    Jon Skeet - <skeet@pobox.co m>
                    Web site: http://www.pobox.com/~skeet
                    Blog: http://www.msmvps.com/jon.skeet
                    C# in Depth: http://csharpindepth.com

                    Comment

                    • Peter Duniho

                      #11
                      Re: Using as operator on value tye array

                      On Thu, 12 Jun 2008 16:01:23 -0700, Jon Skeet [C# MVP] <skeet@pobox.co m>
                      wrote:
                      I'd just like to thank Eric for posting such a complete and
                      illuminating answer.
                      Complete? I read through the whole thing, and I can't figure out if the
                      C# spec is considered to be in error or not. :)

                      That said, I did find the reply interesting and useful. Thanks! However,
                      I'm still confused by some aspects:
                      [...]
                      And in section 4.3 [of the CLR spec?]:
                      >
                      If the class of the object on the top of the stack does not
                      implement class (if class is an interface), and is not a derived
                      class of class (if class is a regular class), then an
                      InvalidCastExce ption is thrown.
                      Is there some typography that got lost here? There's a lot of "class" but
                      without qualification, which makes it hard to understand.
                      =3F
                      2. If Foo can be cast to Bar, then Foo[] can be cast to Bar[].
                      Interestingly, the C# spec has similar language, but only for reference
                      types. This conforms to the CLR spec language, in that coercion isn't
                      allowed but casting is.
                      Where does the spec for castclass say that int32[] can be cast to
                      uint32[]? It doesn't. It should! int32 and uint32 are assignment
                      compatible, so they can be cast from one to the other without changing
                      bits. But they do not implement or derive from each other, so a strict
                      reading of the spec says that this cast should fail, and therefore
                      int32[] to uint32[] should also fail.
                      >
                      Clearly that is not what was meant and not what was implemented.
                      Casting between assignment-compatible types should be legal. Really
                      what this should say is something like =3FIf Foo can be cast to Bar or
                      Foo is assignment compatible with Bar then Foo[] can be cast to Bar[]
                      Why does "assignment compatible" not simply imply "can be cast to"? Isn't
                      "assignment compatible" just a more relaxed (permissive) version of "can
                      be cast to"?
                      Fortunately, the CLR guys did NOT extend this goofy kind of type
                      variance to covariant and contravariant interfaces, which as you know
                      we are probably adding in a future version of C#. That is, if we make
                      IEnumerable<Tco variant in T, it will NOT be possible to do a clever
                      series of casts to trick the CLR into assigning an IEnumerable<int to
                      an IEnumerable<uin t>, even though it is possible to make int[] go to
                      uint[].
                      Interestingly, I think the C# spec might already have this "back door". I
                      noticed it when I was looking at the spec before. I don't recall the
                      specifics, but the basic issue was that an array of type T has an implicit
                      conversion to IList<Sand an explicit conversion from IList<Tback to an
                      array of type S (or vice a versa...I might have that backwards). My
                      recollection is that the only constraint on classes S and T were that they
                      be implicitly or explicitly convertible to the other, as appropriate.

                      But my real question is: are they going to fix the C# spec or not? :)

                      Pete

                      Comment

                      • Jon Skeet [C# MVP]

                        #12
                        Re: Using as operator on value tye array

                        On Jun 13, 1:56 am, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
                        wrote:
                        I'd just like to thank Eric for posting such a complete and
                        illuminating answer.
                        >
                        Complete? I read through the whole thing, and I can't figure out if the
                        C# spec is considered to be in error or not. :)
                        You're right - that was slightly ducked. It looks like the CLR spec is
                        *definitely* in error, and there's an admission that C# would
                        sometimes want to prohibit things that the CLR will admit. I wouldn't
                        like to say whether either of them are likely to be fixed though.
                        That said, I did find the reply interesting and useful. Thanks! However,
                        I'm still confused by some aspects:
                        >
                        [...]
                        And in section 4.3 [of the CLR spec?]:
                        Yup. Partition 3 of ECMA-335. P428 in the PDF, which is P105 of that
                        partition. (It would be so nice if they'd split it into multiple
                        PDFs.)
                        If the class of the object on the top of the stack does not
                        implement class (if class is an interface), and is not a derived
                        class of class (if class is a regular class), then an
                        InvalidCastExce ption is thrown.
                        >
                        Is there some typography that got lost here? There's a lot of "class" but
                        without qualification, which makes it hard to understand.
                        Yes, I the spec has appropriate italics etc in here (and Eric's mail
                        may have done too). Have a look for the relevant section in the spec
                        to get it in all its glory.
                        =3F
                        2. If Foo can be cast to Bar, then Foo[] can be cast to Bar[].
                        >
                        Interestingly, the C# spec has similar language, but only for reference
                        types. This conforms to the CLR spec language, in that coercion isn't
                        allowed but casting is.
                        Right.
                        Clearly that is not what was meant and not what was implemented.
                        Casting between assignment-compatible types should be legal. Really
                        what this should say is something like =3FIf Foo can be cast to Bar or
                        Foo is assignment compatible with Bar then Foo[] can be cast to Bar[]
                        >
                        Why does "assignment compatible" not simply imply "can be cast to"? Isn't
                        "assignment compatible" just a more relaxed (permissive) version of "can
                        be cast to"?
                        I wouldn't like to judge, to be honest. Especially not before the
                        first coffee of the day. Although isn't assignment compatibility
                        possible without an execution time check, whereas a cast might not be?

                        For instance, a reference of type Stream can be cast to MemoryStream,
                        but the two locations involved wouldn't be assignment compatible. (I
                        think.)
                        Fortunately, the CLR guys did NOT extend this goofy kind of type
                        variance to covariant and contravariant interfaces, which as you know
                        we are probably adding in a future version of C#. That is, if we make
                        IEnumerable<Tco variant in T, it will NOT be possible to do a clever
                        series of casts to trick the CLR into assigning an IEnumerable<int to
                        an IEnumerable<uin t>, even though it is possible to make int[] go to
                        uint[].
                        >
                        Interestingly, I think the C# spec might already have this "back door". I
                        noticed it when I was looking at the spec before. I don't recall the
                        specifics, but the basic issue was that an array of type T has an implicit
                        conversion to IList<Sand an explicit conversion from IList<Tback to an
                        array of type S (or vice a versa...I might have that backwards). My
                        recollection is that the only constraint on classes S and T were that they
                        be implicitly or explicitly convertible to the other, as appropriate.
                        There's certainly something around that - and having converted from
                        int[] to uint[] I would imagine you could end up with two variables, x
                        of type IEnumerable<int and y of type IEnumerable<uin twhich are
                        identical references. I might try that later... if it works, I'll post
                        a follow-up to Eric. If I can find a suitably tactful way of wording
                        the "will they fix the C# spec" question I'll ask that too :)
                        But my real question is: are they going to fix the C# spec or not? :)
                        The spec will certainly be changing for covariance etc. If we get the
                        chance to give feedback on a draft, we could try to push for it at
                        that point if it isn't already fixed :)

                        Jon

                        Comment

                        • Peter Duniho

                          #13
                          Re: Using as operator on value tye array

                          On Thu, 12 Jun 2008 23:12:46 -0700, Jon Skeet [C# MVP] <skeet@pobox.co m>
                          wrote:
                          On Jun 13, 1:56 am, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
                          wrote:
                          [...]
                          Clearly that is not what was meant and not what was implemented.
                          Casting between assignment-compatible types should be legal. Really
                          what this should say is something like =3FIf Foo can be cast to Bar or
                          Foo is assignment compatible with Bar then Foo[] can be cast to Bar[]
                          >>
                          >Why does "assignment compatible" not simply imply "can be cast to"?
                          >Isn't
                          >"assignment compatible" just a more relaxed (permissive) version of "can
                          >be cast to"?
                          >
                          I wouldn't like to judge, to be honest. Especially not before the
                          first coffee of the day. Although isn't assignment compatibility
                          possible without an execution time check, whereas a cast might not be?
                          I agree with that assessment...th at's why I'm describing "assignment
                          compatibility" as "more permissive" than an actual cast. Maybe my
                          terminology isn't precise enough, but hopefully the point comes across.

                          But that's my point. The spec already allows for the case where "If Foo
                          can be cast to Bar, then Foo[] can be cast to Bar[]" (at least, that was
                          the text in the message you posted from Eric). So since "assignment
                          compatibility" is already basically a "cast" in a more permissive setting
                          (that is, it works just like a cast, except there's no need for a run-time
                          check), I would think that the array-to-array cast is already explicitly
                          allowed by the CLR spec.

                          Given a particular reading of the spec, at least. :)

                          Yes, there's also the statement about the inheritance relationship, but
                          (having not actually gotten around to downloading and looking at the
                          actual spec) the "2." part in that quoted section from the spec seems to
                          me to supercede the previous paragraph for the array special case.

                          Anyway, thanks for looking into this. It's nice to know people with
                          "friends in high places". :) I look forward to future updates!

                          Pete

                          Comment

                          • Jon Skeet [C# MVP]

                            #14
                            Re: Using as operator on value tye array

                            On Jun 13, 7:36 am, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
                            wrote:
                            I wouldn't like to judge, to be honest. Especially not before the
                            first coffee of the day. Although isn't assignment compatibility
                            possible without an execution time check, whereas a cast might not be?
                            >
                            I agree with that assessment...th at's why I'm describing "assignment
                            compatibility" as "more permissive" than an actual cast. Maybe my
                            terminology isn't precise enough, but hopefully the point comes across.
                            I'm not sure it does. There are times when a cast is permitted but an
                            assignment isn't - doesn't that make casting more permissive in those
                            cases?

                            I'm very glad I'm not the one writing the spec :)
                            But that's my point. The spec already allows for the case where "If Foo
                            can be cast to Bar, then Foo[] can be cast to Bar[]" (at least, that was
                            the text in the message you posted from Eric). So since "assignment
                            compatibility" is already basically a "cast" in a more permissive setting
                            (that is, it works just like a cast, except there's no need for a run-time
                            check), I would think that the array-to-array cast is already explicitly
                            allowed by the CLR spec.
                            Except that the assignment compatibility doesn't imply castability -
                            as Eric pointed out, you can't cast from uint to int (in the CLI spec
                            terms) but the two are assignment compatible.
                            Given a particular reading of the spec, at least. :)
                            And that's the problem, of course. Mind you, if they're fixing up the
                            spec I'd far rather they spent time on the threading aspects than
                            little niggles like this. I've long held the belief that the spec's
                            description of what is and isn't allowed in terms of the memory model
                            leaves rather too much up to interpretation.
                            Yes, there's also the statement about the inheritance relationship, but
                            (having not actually gotten around to downloading and looking at the
                            actual spec) the "2." part in that quoted section from the spec seems to
                            me to supercede the previous paragraph for the array special case.
                            Agreed.
                            Anyway, thanks for looking into this. It's nice to know people with
                            "friends in high places". :) I look forward to future updates!
                            For what it's worth, this wasn't a direct mail to Eric (although I've
                            used that route too in the past - more than I should have, probably).
                            I'll mail you separately...

                            Jon

                            Comment

                            • Peter Duniho

                              #15
                              Re: Using as operator on value tye array

                              On Fri, 13 Jun 2008 01:10:24 -0700, Jon Skeet [C# MVP] <skeet@pobox.co m>
                              wrote:
                              On Jun 13, 7:36 am, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
                              wrote:
                              I wouldn't like to judge, to be honest. Especially not before the
                              first coffee of the day. Although isn't assignment compatibility
                              possible without an execution time check, whereas a cast might not be?
                              >>
                              >I agree with that assessment...th at's why I'm describing "assignment
                              >compatibilit y" as "more permissive" than an actual cast. Maybe my
                              >terminology isn't precise enough, but hopefully the point comes across.
                              >
                              I'm not sure it does. There are times when a cast is permitted but an
                              assignment isn't - doesn't that make casting more permissive in those
                              cases?
                              I guess that depends on your definition of "permissive ". :) Fortunately,
                              it's not a term being used in the spec itself, so the ambiguity isn't a
                              problem. But what I mean is that the code has to do less to get things
                              that are "assignment compatibility" to work.

                              I hate airline security, so I'll use it as an example again: imaging two
                              travelers, one who is pre-screened, paid his "fancy flier" dues, and who
                              gets to skip past most of the security, and another who is like you and me
                              and gets subjected to the long lines, shoes-off, laptop open and running,
                              full pat-down treatment.

                              Which traveler would you say is being treated more permissively?
                              Personally, I'd say it's the guy who didn't go through all the security
                              checks. Likewise, an assignment that is allowed to pass without
                              additional checks is, in my mind, "more permissive".

                              I guess that's a long way of saying that not only is my terminology not
                              precise enough, it's not necessarily getting my point across. Sorry.
                              Except that the assignment compatibility doesn't imply castability -
                              as Eric pointed out, you can't cast from uint to int (in the CLI spec
                              terms) but the two are assignment compatible.
                              CLR or CLI? What's the difference?

                              Anyway, my point is that while the part of the spec Eric quoted, which
                              appears to enumerate those cases where casting is legal, and where casting
                              between assignment-compatible types is not included, does leave out that
                              specific case, it seems to me that _practically_ types that are
                              assignment-compatible are inherently castable as well.

                              Eric seems to be arguing in favor of simply fixing the array language (by
                              adding "assignment compatible" to the short list of type relationships
                              that allows Foo[] to be cast to Bar[]), but it seems to me that it would
                              make more sense to just call out "assignment compatible" as a specific,
                              allowed case of casting. Then the existing array language suffices, and
                              anywhere else that one might find that "assignment compatible" was left
                              out of the language is automatically fixed as well.
                              >Given a particular reading of the spec, at least. :)
                              >
                              And that's the problem, of course. Mind you, if they're fixing up the
                              spec I'd far rather they spent time on the threading aspects than
                              little niggles like this. I've long held the belief that the spec's
                              description of what is and isn't allowed in terms of the memory model
                              leaves rather too much up to interpretation.
                              Heh. Yes, I remember that thread. :)

                              I agree this isn't a big deal...I'm just trying to figure out what the
                              actual "take" on the issue is.
                              [...]
                              For what it's worth, this wasn't a direct mail to Eric (although I've
                              used that route too in the past - more than I should have, probably).
                              I'll mail you separately...
                              Thanks!

                              Pete

                              Comment

                              Working...