Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / July 2007

Tip: Looking for answers? Try searching our database.

this should compile but doesn't

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
not_a_commie - 05 Jul 2007 23:08 GMT
Can anyone tell me what's wrong with the following code? It doesn't
compile. The compiler tries to use the wrong overload. Is it a known
bug? Thanks for your time.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace BadOverloads
{
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
Inherited = false, AllowMultiple = false)]
    public abstract class XmlFormatterAttribute : Attribute
    {
        public abstract string Format(object value);

        public abstract object Unformat(string value);
    }

    public class Program
    {

        public void func(XmlDocument document, XmlFormatterAttribute
attribute)
        {
            Console.Out.WriteLine("func1");
        }

        public void func(XmlDocument document, ref object value)
        {
            Console.Out.WriteLine("func2:" + value.ToString());
        }

        static void Main(string[] args)
        {
            //object testobj = new object();
            //func(new XmlDocument(), ref testobj); // this doesn't work either

            string str = "howdy";
            func(new XmlDocument(), ref str);
        }
    }
}
not_a_commie - 05 Jul 2007 23:12 GMT
In the example code I posted, the two func overloads should be static.
That doesn't fix the problem, though. I find it fascinating that you
get the same error whether or not they're static.
Peter Duniho - 05 Jul 2007 23:27 GMT
> Can anyone tell me what's wrong with the following code? It doesn't
> compile. The compiler tries to use the wrong overload. Is it a known
> bug? Thanks for your time.

I don't think this has anything to do with the abstract class or the  
overloading.  As such, an appropriate, minimal code sample would not  
include them.  Please try to post minimal code examples, as otherwise  
there's a lot of other crud distracting from the issue.

As far as the actual question goes, if you use "ref" or "out" I believe  
that the type has to match exactly.  I presume that this is because if the  
types don't match, an implicit cast has to be made somewhere, but the  
parameter being a reference to some existing variable would not be cast in  
a context where it's simple for the compiler to know it needs to be cast  
(i.e. it would be a run-time thing, too late for the compiler to include  
the implicit cast).

Pete
Jon Skeet [C# MVP] - 05 Jul 2007 23:29 GMT
> Can anyone tell me what's wrong with the following code? It doesn't
> compile. The compiler tries to use the wrong overload. Is it a known
> bug? Thanks for your time.

It shouldn't compile, even if func is static.

The problem is that you're trying to use "ref str" as the argument for
a parameter which is declared as "ref object". You can't do that,
because the method could do:

value = new object();

at which point you'd be stuffed.

I suspect you don't quite understand ref parameters. See
http://pobox.com/~skeet/csharp/parameters.html

Signature

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

Peter Duniho - 06 Jul 2007 00:37 GMT
> The problem is that you're trying to use "ref str" as the argument for
> a parameter which is declared as "ref object". You can't do that,
[quoted text clipped - 6 lines]
> I suspect you don't quite understand ref parameters. See
> http://pobox.com/~skeet/csharp/parameters.html

For what it's worth, I feel like I understand by-value and by-reference  
very well, and I still had to think about the question for a little bit,  
and I still have to do some hand-waving to explain why C# doesn't support  
the scenario.

In particular, take your example "value = new object()" when the parameter  
passed was actually a string.  C# _could_ allow for including type  
information for the original reference when passing by reference, doing a  
run-time cast on any assignments and throwing an exception if the cast  
wasn't successful.  More complicated?  Yes...a lot more complicated.  But  
I don't see anything that fundamentally prevents that scenario.

Similarly, going the other way -- passing a "ref object" when the method  
is declared "ref string" -- the compiler could verify that the "object"  
typed variable held a string before the call, and allow that if it was.  
Even easier, for the "out" keyword, the compiler could just not care,  
since the rules require the parameter to be assigned in the method before  
use anyway (so as long as the passed in variable statically typed to  
something that could hold the method's parameter type, that should be  
okay).

Now, my understanding is that none of this happens.  But it could.

In other words, the restriction that when passing parameters using "ref"  
or "out" the passed variable type needs to match exactly the parameter  
type is somewhat arbitrary.  Worse, it is not documented _at all_.  I  
agree that the restriction can be inferred by thinking about the  
consequences of not having it, but there's nothing in any of the  
documentation I looked at (this includes MSDN's doc pages for the "ref"  
and "out" keywords, your "parameters.html" web page, and the two pages you  
refer to in that page) that explicitly states the documentation.

Pete
Marc Gravell - 06 Jul 2007 05:25 GMT
> Yes...a lot more complicated.  But
> I don't see anything that fundamentally prevents that scenario.

I actually appriate the choice of "keep it simple". For more
complicated scenarios the caller has the capacity (in the object case)
of simply declaring an object variable locally for the duration of the
call, i.e.

string s = "abc";
object obj = s; // perhaps replace with some other base-class
SomeMethod(ref obj);
s = (string) obj; // cross fingers...

Not as succinct, but simple to understand (IMO), plus it can only
break at a point known to the author (which is reasonable, as they are
the ones forcing a square peg into a round hole) - where-as silent
internal casts could start breaking randomly if the SomeMethod author
changes the implementation.

Marc
Peter Duniho - 06 Jul 2007 09:40 GMT
>> Yes...a lot more complicated.  But
>> I don't see anything that fundamentally prevents that scenario.
>
> I actually appriate the choice of "keep it simple".

I do too.  I certainly did not mean to imply that I disagree with the  
design.

I'm just pointing out that this is actually not a very well-documented  
aspect of the language, IMHO.  While, as I said, one can infer the  
behavior by considering the implications of the compiler allowing what the  
OP thinks should be allowed, it's definitely not explicitly stated  
anywhere I looked.

Pete
not_a_commie - 06 Jul 2007 16:40 GMT
> string s = "abc";
> object obj = s; // perhaps replace with some other base-class
> SomeMethod(ref obj);
> s = (string) obj; // cross fingers...

So is the last line of that strictly necessary or only in the case of
value types?
Jon Skeet [C# MVP] - 06 Jul 2007 16:46 GMT
> > string s = "abc";
> > object obj = s; // perhaps replace with some other base-class
[quoted text clipped - 3 lines]
> So is the last line of that strictly necessary or only in the case of
> value types?

It's necessary if you want to use the "s" variable to hold the new
value. (And string isn't a value type.)

Jon
Jon Skeet [C# MVP] - 06 Jul 2007 07:46 GMT
<snip>

> Now, my understanding is that none of this happens.  But it could.

Well, possibly. The runtime would have to pass the type of the variable
instead of just a pointer etc...

> In other words, the restriction that when passing parameters using "ref"
> or "out" the passed variable type needs to match exactly the parameter
> type is somewhat arbitrary.  Worse, it is not documented _at all_.

It is - it's in the C# language specification.

> I agree that the restriction can be inferred by thinking about the
> consequences of not having it, but there's nothing in any of the
> documentation I looked at (this includes MSDN's doc pages for the "ref"
> and "out" keywords, your "parameters.html" web page, and the two pages you
> refer to in that page) that explicitly states the documentation.

Here's a quote from the C# spec, section 14.4.2.1:

<quote>
For each argument in A, the parameter passing mode of the argument
(i.e., value, ref, or out) is identical to the parameter passing mode
of the corresponding parameter, and

 for a value parameter or a parameter array, an implicit conversion
 (§13.1) exists from the type of the argument to the type of the
 corresponding parameter, or

 for a ref or out parameter, the type of the argument is identical to
 the type of the corresponding parameter.
</quote>

Unless you meant that the reasons aren't explicitly documented - in
which case I agree. From memory, it's likely to be in the C# Annotated
Standard which is out soon:

http://www.amazon.com/C-Annotated-Standard-Jon-
Jagger/dp/0123725119/ref=sr_1_1/103-6108362-5713441?ie=UTF8
&s=books&qid=1183704314&sr=8-1

Signature

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

Peter Duniho - 06 Jul 2007 09:47 GMT
>> In other words, the restriction that when passing parameters using "ref"
>> or "out" the passed variable type needs to match exactly the parameter
>> type is somewhat arbitrary.  Worse, it is not documented _at all_.
>
> It is - it's in the C# language specification.

Okay, perhaps "at all" was over-reaching.

However, most people don't read the spec, they read the user reference  
materials on MSDN.  And I do think it's worth pointing out that your own  
page on parameters, which is otherwise a good read, doesn't address this  
at all.  Not directly (though as I pointed out, one can infer the rules  
based on the basic behavior of "ref" and "out", at least if some basic  
assumptions are made).

It's my opinion that the MSDN pages that document the "ref" and "out"  
keywords should both specifically say that there's a requirement that the  
types match exactly.  For bonus points, the page discussing "Passing  
Parameters (C#)" would also mention that requirement.

Pete
Jon Skeet [C# MVP] - 06 Jul 2007 10:09 GMT
On Jul 6, 9:47 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > It is - it's in the C# language specification.
>
[quoted text clipped - 6 lines]
> based on the basic behavior of "ref" and "out", at least if some basic
> assumptions are made).

Righto - I can fix that easily enough. You're right - it's certainly
an omission.

> It's my opinion that the MSDN pages that document the "ref" and "out"
> keywords should both specifically say that there's a requirement that the
> types match exactly.  For bonus points, the page discussing "Passing
> Parameters (C#)" would also mention that requirement.

Can't fix that :( However, you could certainly mail the MSDN
maintainers - click on the link at the bottom of the page and give the
appropriate feedback. It's worked for me a couple of times.

Jon
Christof Nordiek - 06 Jul 2007 10:09 GMT
>>> In other words, the restriction that when passing parameters using "ref"
>>> or "out" the passed variable type needs to match exactly the parameter
[quoted text clipped - 10 lines]
> based on the basic behavior of "ref" and "out", at least if some basic
> assumptions are made).

Actually I searched the programmers reference in MSDN for this issue, and I
didn't even find anything about overload resolution and wich types can be
used in a method call. That docs are sometimes are very poor, regarding such
definitions. But I agree it should be stated there, atleast in a way, that
the most important implication can be induced by it very intuitivly.

Christof
not_a_commie - 06 Jul 2007 16:43 GMT
> Actually I searched the programmers reference in MSDN for this issue, and I
> didn't even find anything about overload resolution and wich types can be
> used in a method call. That docs are sometimes are very poor, regarding such
> definitions. But I agree it should be stated there, atleast in a way, that
> the most important implication can be induced by it very intuitivly.

I think it should be stated clearly in the error message. It appears,
though, that the compiler attempts to use the overloads, though, even
though they aren't a close match, thus obfuscating the original error.
This is particularly confusing for the users.
Peter Duniho - 06 Jul 2007 17:30 GMT
> I think it should be stated clearly in the error message. It appears,
> though, that the compiler attempts to use the overloads, though, even
> though they aren't a close match, thus obfuscating the original error.
> This is particularly confusing for the users.

The compiler will mention "overload" even if there's only one version of  
the method.  I'd agree this is misleading, but it's not unique to this  
particular situation.

I have, by now, been trained to just ignore a mention of "overload", and  
look at the second error generated (they almost always come in pairs :) ).

Pete
not_a_commie - 06 Jul 2007 16:37 GMT
> Now, my understanding is that none of this happens.  But it could.

Thanks Pete. I like you're thinking on this. My $0.02 on making the
compiler handle this: if you can justify immutable variable types
behind the scenes, you can justify autocasting in this case as well.
Jon Skeet [C# MVP] - 06 Jul 2007 16:56 GMT
> > Now, my understanding is that none of this happens.  But it could.
>
> Thanks Pete. I like you're thinking on this. My $0.02 on making the
> compiler handle this: if you can justify immutable variable types
> behind the scenes, you can justify autocasting in this case as well.

But the method being called doesn't know (normally) what the type of
the original variable is - that's part of the problem.

It could cause some very odd-looking bugs, with an assignment which
looks like it should just work failing at runtime.

Jon
Peter Duniho - 06 Jul 2007 17:35 GMT
>> Now, my understanding is that none of this happens.  But it could.
>
> Thanks Pete. I like you're thinking on this. My $0.02 on making the
> compiler handle this: if you can justify immutable variable types
> behind the scenes, you can justify autocasting in this case as well.

Well, just to be clear: "my thinking" in this context (that is, the post  
to which you replied) isn't about what I think _should_ happen.  It's  
about what I think _could_ happen.

There would be a lot more overhead involved in handling the type coercion  
in the way that I describe, since type information would have to be passed  
along with the variable itself, and it would introduce new ways for  
unexpected runtime errors to occurs.

I don't feel that any of this is warranted, since there's an easy  
workaround to the issue: just make sure the types match, and do any  
necessary type-casting explicitly as needed.  IMHO, that provides a  
more-consistent "compiler experience", and is likely to reduce bugs in the  
code as well, since everything has to be spelled out explicitly.

I'm not sure what you mean by "immutable variable types behind the  
scenes".  I'm not aware of any "behind the scenes immutable variables  
types".  But whatever you mean by that, I'm not sure that it leads to a  
logical conclusion that autocasting by-reference parameters is justified.

Pete

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.