views:

176

answers:

4

I am at chapter 9 of Jon Skeet's CSharp in Depth at a section which explains the improvements to type inference in 3.0

There is code snippet on Pg.247 that 'shouldn't compile with 2.0' - However I can't find a reason why it should not. Tried the problem with VS2008 C# Express Edition on a project with target framework as 2.0 - all three of the below calls compile and run too.

2.0 introduced the ability to infer the right type of delegate.

new List<ThreadStart>().Add( delegate { Console.WriteLine("New Thread!"); } );   // works

Of course Jon can't be wrong ( ;) 'Sql is broken' + there is no mention of this on the errata page for the book.) So my prime suspicion would be that it's still using 3.0 type inference - What am I missing ?

    delegate int MyDelegate(string s);
    delegate TOutput MyConverter<TInput, TOutput>(TInput input);
    static void MyParse(MyDelegate del)
    {
        Console.WriteLine(del("100"));
    }
    static void MyConvert<TInput, TOutput>(MyConverter<TInput, TOutput> del, TInput input)
    {
        Console.WriteLine(del(input));
    }

    // Jon's code snippet begin
    delegate T MyFunc<T>();
    static void WriteResult<T>(MyFunc<T> function)
    {
        Console.WriteLine(function());
    }
    // end

    static void Main(string[] args)
    {
        MyParse(delegate(string s)
            {
                return Int32.Parse(s);
            }
        );
        MyConvert(delegate(string s)
            {
                return Int32.Parse(s);
            },
            "100");
        WriteResult(delegate { return 5; });    // Jon: Shouldn't work.
    }
+3  A: 

Don't have my copy of Jon's book, but he'll probably be along soon!

What section is this in? Try looking it up here: http://csharpindepth.com/Notes.aspx

EDIT: Actually, targeting the framework version has nothing to do with the compiler version. So you are still using C# 3.0. The compiler just has to figure out what IL to generate such that it will run on CLR 2.0, and so it can perform as much inference as it likes to do that.

Daniel Earwicker
+3  A: 

I've got Visual Studio 2005 installed on my computer and I just tried out the code that you've posted.

Both MyConvert and WriteResult don't work. I get the following errors:

The type arguments for method 'ConsoleApplication1.Program.MyConvert<TInput,TOutput>(ConsoleApplication1.Program.MyConverter<TInput,TOutput>, TInput)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

and

The type arguments for method 'ConsoleApplication1.Program.WriteResult<T>(ConsoleApplication1.Program.MyFunc<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Praveen Angyan
Well that is what should happen as per the book. Can anyone with VS2008 try this ? - My output windows shows. C:\WINDOWSX\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:TRACE /reference:C:\WINDOWSX\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:C:\WINDOWSX\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:C:\WINDOWSX\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /debug:pdbonly /filealign:512 /optimize+ /out:obj\Release\DotNet2_0_Console.exe /target:exe Program.cs Properties\AssemblyInfo.cs
Gishu
+4  A: 

What the 'target framework' setting does, is disable libraries and methods that have been added in newer framework versions. Most of the new language features don't require special runtime support or new libraries. So if you use them, you need the newer compiler, but your app will still work on 2.0.

Zr40
Just finished commenting on this :) how do I try out such things with VS2008 in that case...
Gishu
You can't, VS2008 always uses the 3.5 compiler. You need VS2005 if you want to use the 2.0 compiler. You could also run the 2.0 compiler via the command line.
Zr40
Yeah I needed to switch to console mode, traverse to the project folder, copy the compilation command from the VS output window, replace the 3.5 compiler exe path with the 2.0 compiler exe path and now it fails as expected.
Gishu
+3  A: 

There are several different versions involved here:

  • The IDE: Visual Studio 2008
  • The .NET framework: you're targeting .NET 2.0
  • The CLR: you're targeting 2.0 (ignoring service packs :)
  • The C# compiler you're using: Visual Studio 2008 always uses the C# 3.0 compiler
  • The language version the compiler is targeting: 3.0 by default

To see type inference fail without going back to the version 2.0 compiler, you need to make the C# compiler use version 2 of the language. I don't know if the express edition of Visual Studio exposes this, but you can use the command line to see it.

Unfortunately - and this is really weird - I now can't reproduce the difficulty that way either.

Here's what I just tried:

using System;

class Test
{
    public delegate T Function<T>();
    public static T Execute<T>(Function<T> function)
    {
        return function();
    }

    static void Main()
    {
        Execute(delegate { return 5; });
    }
}

I'd expected that compiling with

csc /langversion:ISO-2 Test.cs

would fail... but it doesn't. This does fail with the real C# 2 compiler:

>c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc Test.cs
Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.3053
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

Test.cs(14,9): error CS0411: The type arguments for method
        'Test.Execute<T>(Test.Function<T>)' cannot be
        inferred from the usage. Try specifying the type 
        arguments explicitly.
Jon Skeet
It does. Only that I've to go to command line and manually invoke the 2.0 compiler ; see my comment on the acc answer..
Gishu
So does this sound like a bug in langversion to you? It does to me... will ask Eric.
Jon Skeet
The question however still remains unanswered... forgot about that. So the reason that this doesn't compile under 2.0 is that the 2.0 type inference mechanism does not consider return values of anonymous methods ?
Gishu
2.0 type inference does not make any inference from an anonymous method argument.
Eric Lippert
All that "langversion" does is turn off some features of the PARSER. The SEMANTIC ANALYZER is exactly the same no matter what the switch is set to. If what you want is the exact semantic behaviour of 2.0, well, you've got the compiler on your machine, so go use it! :-)
Eric Lippert
@Eric: Ah - that's worth knowing. It feels like that makes it a considerably less useful switch, but at least I know about it now :)
Jon Skeet
Interesting comment-thread this.. so this means if i have the latest version / VS2008 but need to write apps for 2.0 (let's say we need to support an 'older' OS) - there is no way to be positively sure that you're not using any newer features.. apart from going back to a VS2005 environment. Sounds painful..
Gishu
@Gishu: What kind of 2.0 are you trying to support though? Framework 2.0 is easy enough (at least framework 2.0SP1). It only supporting fellow developers who need to *compile* with 2.0 which is tricky.
Jon Skeet
The need is to write apps on a framework v3.5 environment that will run as expected on target machines with framework v2.0 - this means not having any method missing exceptions (due to usage of newer overloads n stuff), using new IL instructions, that sort of thing. Somehow keeping it bound to only the 2.0 feature set.
Gishu
@Gishu: You're still confusing 2.0 of the *framework* with 2.0 of the *language*. If you target .NET framework 2.0 in Visual Studio, you should be fine. This question is about what the *compiler* is willing to do. You can use plenty of C# 3 features when targeting .NET 2.0 - the CLR doesn't know or care whether you used a lambda expression to create a delegate instance, for example.
Jon Skeet
Sorry to go on and on about this.. I've seen a couple of instances of dependencies leaking in when targeting a specific version of the fwk. It seems that it was a bug and an FXCop rule to counter it now. http://davesbox.com/archive/2008/08/25/new-for-visual-studio-2008-sp1-and-fxcop-1-36-multi-targeting-rule.aspx
Gishu
Yes, the service pack business is certainly unfortunate - but my point is that those are *framework* dependencies. In the case of type inference, this is just the compiler being a bit smarter in C# 3: the results of that smart inference are valid on *any* 2.0+ CLR and framework.
Jon Skeet