Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
ljw1004
Jan 18, 2005

rum
I'm happy to talk about async design! Thanks for the comments, Malcolm and others. I love the chance to talk about language design. Looking back, I think we made the right calls at the time, and right now I'd make mostly the same calls again...


Malcolm XML posted:

Stupid things like configure await and having to manually spill variables (!!!!) to reduce allocations is just tedious

ConfigureAwait? There's a straightforward choice: either optimize the design for app authors (by returning to the original thread/context after an await), or optimize the design for library authors (by continuing after the await on whichever thread/context you happen to be). We chose to make things easier for the app authors, because there are more of them and because they're less expert.

Within the .NET framework, they use .ConfigureAwait(false) everywhere. Using the new "Roslyn Diagnostics" feature (as in Dev14 CTP1) you can add custom rules to your project, including e.g. enforcing that every await has a .ConfigureAwait() after it. Within VS, actually, they don't enforce this... the people there came up with a different pattern they think is more robust. They're still refining it. Maybe in a month or so I'll be able to post what they've done.


Manually spill variables to reduce allocations? There's a straightforward choice: either allow await in arbitrary places e.g. "using (var x = await GetFileAsync())" and deal with the consequences, or do what F# did and only allow it in two places "do!" and "let!". We chose to allow it everywhere because this was the biggest complaint in F#. We can still optimize the compiler further to make it more efficient when you use await in weird places, e.g. "myStructArray[await i].f(await j)", and indeed we've already made improvements in await codegen for Dev14 CTP1, but it's a case of diminishing returns.

Is it tedious to write awaits in a way that don't involve spilling? Not really. You can still write "var x = await <expr>" and "await <expr>" and "using (var x = await <expr>)". It really is only the more esoteric code patterns, ones that usually don't pass code review, that involve spilling.



quote:

Also it conflates a CPS rewriting sugar (await) with parallelism which honestly is more confusing. Something along the lines of haskell async or parallel might have been cleaner

Conflate CPS with parallelism makes it more confusing? I strongly disagree. The whole world has been on a stupid mistaken bender over the past decades, stemming from the mistaken belief that asynchrony means multiple threads. I know... I suffered through it for my undergrad, PhD and postdoc, and saw countless research careers stupidly wasted on this misconception. About half the people still don't get it, and write bad (inefficient) code as a consequence.

Look, if you're in a restaurant and need to serve two tables, do you hire TWO waiters? No. You use the same one cooperatively for the two tables. It's an easy enough concept in real life. It should be easy in code. It will be easy to people who are brought up thinking this way (including node.js developers!)


quote:

I just don't think it's at all clear how async await works behind the scenes and how much control you have over it: the actual generated code is not even CPS it's a funky state machine with a bunch of gotchas.

The semantics of await are precisely "CPS with a one-shot continuation", no more, no less. The "funky state machine" is as funky as it needs to be to optimize performance, no more, no less. The only gotcha I can think of is if you write a custom awaiter that's a mutable struct, but mutable structs are always dodgy.

Here are two blogs I've written with more information about "behind-the-scenes". They're on my blog not part of official cleaned-up MSDN documentation because honestly they're needed by almost no one except Jon Skeet to set brainteasers about.
http://blogs.msdn.com/b/lucian/archive/2012/12/12/how-to-write-a-custom-awaiter.aspx
http://blogs.msdn.com/b/lucian/archive/2013/11/12/talk-async-codegen.aspx


quote:

It needs some nicer combinators and good spec of its semantics

Combinators? Here I think you're way off the mark :) You should compare "await" to "callbacks". Awaits are COMPOSITIONAL with respect to the other operators of the language in a way that callbacks are not. The word "compositional" comes from computer science theory... what it boils down to in practice is that with callbacks you can't continue to use your familiar try/catch blocks, or while loops, or for loops, or even the goddam SEMICOLON operator. You have to figure out other weird ways to encode them. Callbacks are not compositional with respect to most of the language operators. By contrast, await is compositional with respect to them.

As for the combinators? They're all present in Task.WhenAll / Task.WhenAny / Task.Delay / ... Indeed the whole great thing about async/await is that, through the Task type, it has such a plethora of great combinators! TPL Dataflow! All of them!

As for a spec of semantics? With Neal Gafter's help (of Java fame) I wrote the VB language spec for async+await and I think I did a pretty good job. Mads wrote the C# spec for it and also did a pretty good job. Please let us know if you think it's underspecified.


Bognar posted:

I really like what async/await gives you, but I do agree that there are some nasty hidden gotchas. My main complaint is that you're not able to easily call an async method synchronously. Doing that is basically a recipe for deadlocks, but what option do I have if I'm not running in an async ready context (e.g. console app)? This forces most libraries to expose both synchronous and asynchronous method calls which just pollutes their APIs. If calling asynchronous methods synchronously was easy then we could get rid of this silly *Async duplicate method convention and just expose async methods.

What you're seeing is an underlying "gotcha", that async+await makes more manifest. In the case of a console app, I personally just do this:
code:
Module Module1
   Sub Main()
      MainAsync().GetAwaiter().GetResult()
   End Sub

   Async Function MainAsync() As Task
      ... write my code here
   End Function
End Module
That's easy, but doesn't have the nice "single-threaded" guarantee you normally get as an app author. If you want that, then you'll have to create your own message-loop as described here:
http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

We discussed whether or not to make async console apps easier to write, by providing that message-loop by default, but there's no good consensus on how exactly it should behave, so we didn't.


Libraries should not generally go around offering both sync and async versions of their APIs, and indeed most don't...
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Async-Library-Methods-Shouldn-t-Lie



Malcolm XML posted:

They tried to get monads in the language with linq and it was ok but I have rarely seen generators (and the difference between Ienumerator and ienumerable is subtle and almost always you actually want the former) Now they've gotten a monad that isn't really a container and in order to sneak it in without the ability to have do-notation they put in await which manually performs CPS and then optimizes it out by using a state machine analogous to yield return

Exposing monads to programmers never makes their lives easier! No matter how many times Erik Meijer says it! Same goes for the rest of category theory! (I spent many hours struggling through Benjamin Pierce's book "Category Theory Made Simple So That Even Dumb Computer Scientists Can Understand It", and attended category theory seminars at college, and roomed with a category theory PhD friend, and I still don't buy it...)


quote:

And then there's synch context which is really goddamned subtle and even Jon loving skeet says he doesn't really understand it so how do you expect workaday devs to diagnose why deadlocks are happening in something they were sold as the best asynchronous pattern?

It's really not hard to avoid deadlocks. Just stop using .Wait() and .Result. Heck, write a Dev14 CTP1 analyzer plugin to enforce this if you want!

Deadlocks aren't a significant problem in the wild. In my opinion the more significant problems are (1) re-entrancy bugs, (2) people failing to understand the difference between CPU- and IO-bound code.



quote:

I wanna say if they dropped the async void compat layer and made it so that async behaved more like Haskell async by using speculative parallelism it might be better

Speculative parallelism? A huge dead end, based on the misconception that having lots of your codebase be multicore-able is somehow worthwhile. Turns out it's not. We also pursued other similar approaches, e.g. doing memory heap shape analysis to discover which methods can be executed in parallel. Wasted a good dev for a whole year on it.

In the end, you actually get the bulk of your parallelization benefit from just the small computational inner-loops in your code, the ones that iterate over large datasets. And these are best expressed in domain-specific ways and coded by experts, e.g. PLINQ, or calling into a lock-free sorting algorithm, or similar. Trying to put multithreading (implicit or explicit or "hinted at") into the rest of your code gives negligible performance benefits, but at huge cost in terms of bugs and race conditions and mental complexity. Not worth pursuing.


Malcolm XML posted:

F# had async workflows, which are really nice and much better for a lot of async stuff than the TAP :http://tomasp.net/blog/csharp-async-gotchas.aspx/

We started from F# async workflows, fixed up the chief complaints with them, aggressively improved their performance to within an inch of their lives, and then made the concessions needed to bring async into the mainstream. VB/C# async is the result.

From Tomas' blog...

Gotcha #1: This is the point that C# async methods don't yield control until they hit their first not-yet-completed await, while F# async methods yield immediately. We did this very deliberately because it makes await vastly cheaper:
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Async-libraries-APIs-should-be-chunky

In any case, both the F# and the C# code are ugly for mixing blocking and async stuff in them. This isn't the way anyone should be writing code, and Tomas is wrong to call it out as a benefit of F#.


Gotcha #2: Out of date. The C# and VB compilers both warn about the failure to await.


Gotcha #3: The fact that we allow async void. Tomas trumpets it as an achievement that you have to write 8 extra lines of pointless boilerplate to use async in real-world code. I don't think that's an advantage. The right solution is (as we did) allow async void as a painful concession to back-compaq. On a project-by-project basis you might want to opt in to more aggressive compile-time warnings about it; that's what Dev14 CTP1 diagnostics are all about.


Gotcha #4 and #5: The problem that in C# an async lambda might be a void-returning async, if it's passed to a parameter of type Action. Yes this is a shame, but it's an unavoidable consequence of earlier design decisions in C#. And in any case, like he shows with Task.Run instead of TaskFactory.StartNew, the solution is always simply to use the more modern APIs whose overloads are designed to be async-friendly. (alas this doesn't work with WinRT which isn't technically able to have such async-friendly overloads for irritating reasons).


Gotcha #6: The fact that we used the Task type, which has blocking Wait method on it. Sure. But the advantages were huge of buying into the whole Task ecosystem, and its many powerful combinators, and these benefits were TOTALLY worth it.

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum

Scaramouche posted:

I'm using StringBuilder to concatenate a whole biggo bunch of strings, converting that StringBuilder.tostring, and then writing the resultant string to an XML file. I'm sure many of you know what's coming next since I said "biggo" and "StringBuilder"; that's right, the dreaded 'System.OutOfMemoryException' caused by StringBuilder over-allocating contiguous memory.

I think you should change it to using streams throughout.

code:
Using fs As New FileStream("file.xml"), sw As New StreamWriter(fs)
 sw.AppendLine("<?xml version=""1.0"" ?>") 'etc start tags
 For Each drThinger In dtThinger
   'About 2000 lines of if/then, case statements, value lookups, and translations, most of which look like:
  If drThinger("value")="other value" then
   sw.AppendLine("<Thinger>whatever value=othervalue means</Thinger>")
  End If
   'Repeat 80,000 times
 Next
 sw.AppendLine("stuff") 'etc end tags
End Using
Incidentally, since you're using VB, you might find it easier to write some of it using XML literals. Or might not...

code:
   sw.AppendLine(<Thinger key=<%= value%>>hello <%= x %></Thinger>)

ljw1004
Jan 18, 2005

rum

Newf posted:

My prejudice towards sets here probably comes from my math background. I do recognize that it's better practice to use a dictionary, specifically for the reason Ithaqua mentioned of constructing lovely hash codes. In this case though, the hash code is just inheriting from String.GetHashCode(), so there's no chance that it's bad...

There is a chance that it's bad! e.g.

code:
class C {
   public string s {get; set;}
   public override int GetHashCode() {return s==null ? 0 : s.GetHashCode();}
}
This is bad because if ever the string changes while an instance of "C" is inside the HashSet, then it will be in there under the previous has-code rather than the new one.

The general rule is: only compute GetHashCode from fields/properties that are guaranteed not to change after construction, e.g. because they have the readonly modifier

ljw1004
Jan 18, 2005

rum

JawnV6 posted:

I have a C program that compiles cleanly on Linux/OSX. I need it to run on Windows. There is some light file i/o and a lot of usage of a COM port.

I am familiar with C#'s COM port handling and so far I'm able to communicate to the device. Before I get into the heavy lifting of duplicating the C program's functionality in C#, is there a lighter path than this? I've spent two nights on skype trying to walk a technician through using this under linux and a rewrite is looking better and better.

When I ported C code from linux to windows, I just kept it in C/C++. If it already used FILE* in C, then it was easy to make that work under windows. (However I never did any COM port stuff). I didn't understand from your post why you also want it in C# ?

ljw1004
Jan 18, 2005

rum

Factor Mystic posted:

What? There's no need to use the F# console. This is basically what the Immediate Window is for, but you do have to be debugging.

That's not true! You can use the Immediate Window "immediately" without debugging...

(1) Launch VS. You have to load a project -- any old project will do.

(2) Debug>Windows>Immediate (or use its shortcut Ctrl+G)

(3) type in your expression, e.g. "? System.IO.Path.GetInvalidFileNameChars()"



Note: under the hood, it automatically builds your project and runs the immediate window against your project, so yes technically speaking it us debugging you just don't notice it. What this means is that, if you had defined any methods or types in your project, then you can call them from the immediate window. For instance, define "class C {}" in your code, and then try writing "? new C()".

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

How do you guys save little reusable blurbs of code to use through various projects? A class library would work with static methods but that seems like a pain to maintain. Does VS have something like this built in?

I blog about it! Or write a codeproject article. That's been my most reliable way to re-use code over the past twenty years...

ljw1004
Jan 18, 2005

rum

gariig posted:

InitClass will be called at startup because the runtime wants to create the variable initialized.

Wait, what? That's not what the link says. It says:

MSDN posted:

As is the case with all class types, the type information for a static class is loaded by the .NET Framework common language runtime (CLR) when the program that references the class is loaded. The program cannot specify exactly when the class is loaded. However, it is guaranteed to be loaded and to have its fields initialized and its static constructor called before the class is referenced for the first time in your program

In practice, the JIT compiles a method only at the first time the method is invoked. At that moment it first chases down every type that's touched by the method, and ensures they're all loaded. The type-load process will invoke all static constructors (hence, will initialize all static variables).

I don't know when static constructors are invoked in ProjectN (native compilation of C#)

ljw1004
Jan 18, 2005

rum

Essential posted:

I have a data upload process I need to run at a certain point and I need to check every 30 seconds if it's time to upload. Then when I am uploading data I don't want to check again until the process is complete. Once complete I need to start checking every 30 seconds again.
What do you guys typically use in this situation?

I hate callbacks. What you're describing is a "process" or "workflow". I do all of these with async, because that I way I can code my workflow algorithm using familiar constructs like "while":

code:
// launch the async worker at application startup:
StartUploadWorkerAsync();


async void StartUploadWorkerAsync()
{
   while (true)
   {
      await Task.Delay(30000);
      if (!timeToUpload) continue;
      await DoUploadAsync(...);
   }
}

ljw1004
Jan 18, 2005

rum

Ithaqua posted:

Does anyone have any ideas about getting around SignalR's inability to have async event handlers? I'm working on something where I have my application's logic totally platform-agnostic and want to fire events when the internal state changes and needs to be pushed to clients, but SignalR can't handle async void methods.

I've seen that other people have suggested code snippets but I still don't understand the actual problem, Ithaqua.

It sounds like your app is running on the server. Periodically you want it to send out events to all the clients when an internal part of your app changes. Do you want your app to pause until all clients have received the event? Presumably not. Presumably you just want to fire-and-forget some kind of event.

And which part of SignalR exactly isn't handling async void methods? If everything really is just fire-and-forget, what are you awaiting?

ljw1004
Jan 18, 2005

rum

TheReverend posted:

Hey folks,
I have a C++ library that I'm supposed to use.
Problem is, we do everything in C#.

Is there a good way to use this library that isn't "wrapper class" because it has way to many functions,classes,stucts,enums,etc that making a wrapper class would be awful.

Any tools or tricks? Please :ohdear: ?

Start with the PInvoke Interop Assistant
http://clrinterop.codeplex.com/releases/view/14120

The idea is that you paste C++ code into the assistant, and it spits out C# interop code. It will spit out C# interop code for structs, enums, functions, COM interfaces. Then you can invoke them directly.

As for classes? I think you're stuck here. It's fine for C# to call a C-style function directly, but there's no way for C# to call a C++ class member directly. You'll have to write a wrapper.

ljw1004
Jan 18, 2005

rum

Gul Banana posted:

I was really sad to see in Roslyn dev notes that VB.NET is not getting any equivalent to this feature :(

Sorry, that was partly my doing. The reason for not doing them in VB is:

* We foresee something nicer coming along, e.g. https://roslyn.codeplex.com/discussions/560339
In C# the primary constructor syntax will already be taken, so C# would have to express "plain old data" objects with some kind of other syntax e.g. "record class Point(int x, int y);" and there'll be several similar kinds of things. In VB, if we don't do primary constructors now, then we'll leave the syntax free for the something nicer in the future.

* VB already lets one member initializer refer to another, e.g.
code:
Class C
   Public X% = 15
   Public Y% = X + 5
End Class
If we had primary constructors, and the lowercase name "x" was used for it, then the above initialization of Y would now refer to that primary constructor parameter x rather than to the member.

* VB isn't case sensitive and so can't rely on different casing conventions like C# has for constructor parameters vs members

* There are a bunch of things that don't quite work right, e.g. you can't do XML doc-comments right on primary constructors. And by the time you start putting in complicated type names e.g. "Class C(x As List(Of Tuple(Of IDiagnosticProvider, ISymbol)))" then it's pretty wordy.

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

I think this the right place. I'm having some trouble with XAML since I'm completely new to it. Specifically I'm having trouble with the data binding.

I think people make data-binding more difficult than it need be. Here's how I'd write your code...

XML code:
<Page
    x:Class="CompanyWidgetMobileApp.MarginCalculatorPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CompanyWidgetMobileApp"
    xmlns:data="using:CompanyWidgetMobileApp.Data"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <data:SampleMarginData x:Key="data1"/>
    </Page.Resources>


    <ListView x:Name="list1" d:DataContext="{StaticResource data1}" ItemsSource="{Binding}">
      <ListView.ItemTemplate>
        <DataTemplate>
          <Grid Background="DarkBlue">
            <TextBlock VerticalAlignment="Top" Text="{Binding Item}"/>
            <TextBlock VerticalAlignment="Bottom" Text="{Binding SalesCost}"/>
            <Image HorizontalAlignment="Right" Source="{Binding Price}"/>
          </Grid>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
</Page>
This means: (1) Instantiate an instance of the "SampleMarginData" class and have this instance go by the name "data1". (2) At design-time, use "data1" as the datacontext for my listview.

(I deleted all the data-context stuff you had)

(3) At runtime, in my page constructor on Loaded or OnNavigatedTo event, then I'd bind list1.DataContext to my actual runtime datacontext.

And here's the code I'd write:

C# code:
namespace CompanyWidgetMobileApp.Data
{
    public partial class MarginModel
    {
        public ItemModel Item {get; set;}
        public double SalesCost {get; set;}
        public double SalesPrice {get; set;}
    }

    public class SampleMarginData : ObservableCollection<MarginModel>
    {
        public SampleMarginData()
        {
           Add(new MarginModel {Item=new ItemModel(), SalesCost=23.1, SalesPrice=17.9});
           Add(new MarginModel {Item=new ItemModel(), SalesCost=11.1, SalesPrice=23.1});
        }
    }
}
I've written the "MarginModel" class using auto-properties, which the compiler treats as a syntactic shortcut for the longhand form of the properties that you were writing out in full.



Why do people use json for their sample data? Beats me.



CAVEAT: I've not used sub-namespaces within XAML. So I don't know if this "xmlns:data" declaration is the right way to do it. I generally stick all my stuff just in the main project namespace, and so my XAML would have "<local:SampleMarginData x:Key="data1"/>"

ljw1004
Jan 18, 2005

rum

Drastic Actions posted:

The easiest thing to fix right now is getting rid of hard coded strings and putting them into the resources files. They originally did not have any and everything was hard coded into English in the XAML. I built the English and Japanese Resw files

DON'T USE RESW DIRECTLY!

You should have the single primary language in RESW, and then use XLF files (from the Multilingual App Toolkit) for all other languages. XLF+MAT is the only sane way to manage your translation workflow.

ljw1004
Jan 18, 2005

rum

Scaramouche posted:

This is a relatively simple question, but I can't seem to google-fu my way to an answer. [snip]

It looks like TextFieldParser doesn't actually buy you much in this situation, and is more trouble than it's worth. I'd do it like this:

code:
Using afile As New IO.StreamReader("TextFile1.csv")
    afile.ReadLine() ' discard the first row, which contains column headings
    While Not afile.EndOfStream
        Dim line = afile.ReadLine()
        Dim csv = line.Split(","c)
        If csv.Count <> 3 Then Continue While
        Console.WriteLine("{0}...{1}...{2}", csv(0), csv(1), csv(2))
    End While
End Using
You'll need some heuristic for how to detect column headings, and blank lines, and subtitles. In your code your heuristic was to look for the exact content. I picked different heuristics in the hope that they'd be more general (i.e. wouldn't need you rewriting your code when the CSV starts looking slightly different).

ljw1004
Jan 18, 2005

rum

epalm posted:

My question is why can't I use GET and send a complex type? For example say I'm running a search with a list search terms.

I don't even understand if you're talking about client-side or server-side, and which language you're writing in...


Sure you can send a complex type in a GET url.

ljw1004
Jan 18, 2005

rum

Bognar posted:

Generally, you shouldn't JSON.stringify if you're using jQuery AJAX to GET. GET commands are (de)serialized as application/x-www-form-urlencoded because they have to be part of the query string

Should I feel bad that my strong instinct in this case is to make a request of the form

code:
"/path/to/mymethod?query=" + uriEncodeComponent(JSON.stringify(...))
And then write my ASP.Net WebAPI or MVC to retrieve it like this

code:
[HttpPost]
public PartialViewResult MyMethod(string query)
{
    var s = HttpUtility.UrlDecode(a.Replace("%20","+"));
    var json = JSON.Parse(s); // or whatever
What this loses is that the query string, although still mostly human-readable, is marginally less readable. What it gains is that it works and you're in precise control over the exact serialization/deserialization format.


I always get confused over the exact correct uri encoding/decoding stuff. I followed what I read here:
http://stackoverflow.com/questions/86477/does-c-sharp-have-an-equivalent-to-javascripts-encodeuricomponent

ljw1004
Jan 18, 2005

rum

Factor Mystic posted:

What's a good technique to parallelize a recursive, async retrieval task? I'm loading hierarchical items (folders of items & folders) from a remote resource, and there's wait time associated with getting a folder's children.
...
Doing something like "await Task.WhenAll(folders.Select(LoadStuff))" seems to balloon the number of threads in use, but I assume that's capped by thread pool availability anyway.

"Balloon the number of threads" is a surprise to me. The await operator doesn't create new threads. Task.WhenAll doesn't create new threads. The general principle is that no keywords in C# create new threads, and only a few specific clearly-identified functions like "Task.Run" will allocate anything on the threadpool. So where did your mysterious ballooning threads come from? I don't know. There might have been other threads being used under the hood, due to misbehaved APIs, but it's hard to know without a debugger.

Stepping back, let's examine the problem from a theoretical angle. By the time your algorithm completes you will have issued "N" total calls to the remote resource and they will have completed. No amount of parallelization will ever change this total number "N".

You believe that your remote resource can typically handle a higher rate of concurrent requests than just simply doing those N requests one after the other. This is a reasonable belief and true of most servers. So what is the optimum number of parallel requests? Impossible to say. We don't know if the server will be fielding requests from other clients at the same time. We don't know if the server will reject requests if it's busy, or queue them up. It's likely not a good use of resources to implement our own rate-adjusting throttling mechanism to determine on-the-fly the optimum number of requests (like the throttler in TCP/IP does).

The best practical answer, one that works great in most situations, is just pick a number. Let's say "3" parallel requests. If the server takes time "t" for each request, then you'll finish in about N*t/3.


Here are two idioms for throttling async stuff. The first looks stupid, but it's clear and works and doesn't need new abstractions and is robust, and that in my book is a good pattern :) If you run it all on the UI thread then you don't even need to worry about using concurrency-safe data structures. For instance, you can use a normal (non-concurrent) queue, and your ProcessWorkItem method can happily add things to an ObservableCollection that's databound to the UI.

code:
async void Button1_Click() {
    var t1 = WorkerAsync();
    var t2 = WorkerAsync();
    var t3 = WorkerAsync();
    await Task.WhenAll(t1,t2,t3);
}

async Task WorkerAsync() {
   while (queue.Count>0) {
      var i = queue.Dequeue();
      ProcessWorkItem(i);
   }
}
In your case, you described your problem recursively, but I've implemented it non-recursively. Just make a queue of all outstanding folders that have yet to be processed. In your "ProcessWorkItem" function, you can retrieve all child folders, add them to the queue, then retrieve all child files.



Here's another solution for throttling based on the "Dataflow" library from Microsoft. Dataflow is powerful and you can wire it up in more sophisticated ways. It runs the callbacks on the threadpool. But again, you're still turning the recursive thing into something queue-based.

code:
private static async Task LotsOfWorkAsync()
{
    ITargetBlock<Folder> throttle = null;
    throttle = Throttle<Folder>(
        async folder =>
        {
            // handle the folder by posting further folders to the throttle
        },
        maxParallelism: 3);
    throttle.Post(top_level_folder);

    // Signal that we're done enqueuing work.
    // Actually, I don't know where best to call this function.
    // You'd call it when there are no more items left to enqueue.
    // I don't know how to figure that out cleanly.
    //throttle.Complete();

    // Don't complete this async method until the queue is fully processed.
    await throttle.Completion;
}

private static ITargetBlock<T> Throttle<T>(Func<T, Task> worker, int maxParallelism)
{
    var block = new ActionBlock<T>(worker,
        new ExecutionDataflowBlockOptions {
            MaxDegreeOfParallelism = maxParallelism,
        });
    return block;
}

ljw1004 fucked around with this message at 05:41 on Sep 5, 2014

ljw1004
Jan 18, 2005

rum

Factor Mystic posted:

I don't know either. Perhaps I was misreading the my debug print statements, which also print the current Environment.CurrentManagedThreadId. Normally the highest id's I see are 7-8. With the WhenAll approach, the id's climbed steadily up into the 80's before I killed the process.

I suppose my report could be inaccurate if the managed thread id doesn't reliably indicate which native thread is running and could tick higher even when reusing the same native thread at a later point, but poking around the reference source sure seems to imply that it's referring to a native thread.

I'm not sure which reference source you're looking at? The .NET reference source only says that the getter of CurretManagedThreadId is "extern". In any case, when you look at the debugger window, you usually see higher CurrentManagedThreadId than there are threads. This proves either that your way of testing isn't accurate or that the VS debugger fails to show all threads. I reckon the way of testing isn't accurate :)






quote:

Yes, this seems like the most obvious approach, however I believe it'll be preferable to run queue consumption on another thread. (A detail which I left out of my example case is that this code is already running on a background Task thread, not on the UI thread. Since this is really more of a patterns question, it didn't seem super relevant. The reason is UI responsiveness. The OC<T> in my example is not databound in the UI. Not relevant details for a pattern question).

I reckon there's almost never a good reason to run your work on a background thread, and lots of bad reasons. Here are slides from a recent talk I gave to the Windows XAML team:






FACT: doing asynchronous work on the UI thread, i.e. using the await operator, will NEVER harm UI responsiveness, not even on the lowest-power device you'll find. The only things that harm responsiveness are when you have "10s" or "100s" concurrency (e.g. if you throttle up to 100 concurrent requests). Or when you have code which blocks a thread.

The only code that blocks a thread is (1) calling blocking APIs - in which case rewrite your code to use async APIs; or (2) doing a CPU-bound computational kernel - in which case do this small computational kernel inside Task.Run.

What you can end up with is an architecture where the orchestration of the app is done entirely on a single thread (i.e. all the awaiting, data-binding, app-logic, ...). And only the small computational inner-loops are done on the threadpool using Task.Run. This architecture will have fewer concurrency bugs and easier-to-read code.

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

So I'm on a deadline trying to learn async programming for the first time :downs:
Anyone see what I'm doing wrong here? I understand a little bit of how this works, but I'd probably go non-threaded if I could.

1. Async should be "async all the way down". Don't make calls to blocking APIs. If you have some CPU-bound work, put it inside "await Task.Run(...cpu-bound computationally intensive inner loop)". So the first change is
code:
content = await reader.ReadToEndAsync();
If you don't do this, then your GetSettingsFromConfigFile method will block the thread (maybe even the UI thread) waiting for the file to be read off disk.

2. Do you really truly want to use a config file? You could instead decide to save stuff like this, which is easier, works with strings, and is good for up to 8k per setting:
code:
ApplicationData.Current.LocalSettings.Values["index"] = 15;
3. Convention is to name async methods with the "Async" suffix:
code:
public async Task<JsonObject> GetSettingsFromConfigFileAsync(string configFilePath)
4. Your GetJsonValueFromServer is pretty weird in a number of ways...

You're using HttpWebRequest.BeginGetResponse with "GetServerCallback". This makes it impossible for your method to return a JsonObject (since the returned object won't be available when GetJsonValueFromServer returns; it will only be available when the OS invokes your GetServerCallback method). You observed this problem when you had to "return null" from your method. In any case, it's better to await an async API instead.

Your "ServerUrl" object is presumably a field, which makes me scared! It should most likely be a local variable, yes?

You used "Task.Factory.StartNew" which is positively dangerous when you pass in an async lambda. You should instead use Task.Run.

I don't think there's benefit in using HttpWebRequest. I'd advise to use HttpClient.

So here's how I'd rewrite the method...

code:
public virtual async Task<JsonObject> GetJsonValueFromServerAsync(string outJson)
{
    JsonObject settings;
    settings = await GetSettingsFromConfigFileAsync();
    var ServerUrl = settings["Server"].ToString();

    var http = new HttpClient();
    var response = await http.GetStringAsync(ServerUrl);
    return JsonObject.Parse(response);
}
5. Is it really worth using the Windows.Data.Json.JsonObject API? My instinct is to prefer Newtonsoft's Json.NET (by doing AddReferences > ManageNugetPackages and searching for Json.NET)


6. Is it worth making "content" a variable outside the "using" clause? Here's how I'd have written it:
code:
var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(configFilePath);
using (StreamReader reader = new StreamReader(myStream))
{
    var content = await reader.ReadToEndAsync();
    return JsonObject.Parse(content);
}

quote:

I can't seem to run through the debugger. It won't let me "f10" over "string content = String.Empty;" (errors happen below upon doing that) and "return JsonObject.Parse(content);" never hits its breakpoint.
Ouput windows says this:
code:
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.ni.dll
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.ni.dll
I assume this has to do with async ignorance.

I have no idea what's going on with this. It might be worth checking whether you're on Debug or Release mode (since F10-stepping gets a bit screwed up with Release mode because it can't always tell where a given statement starts or ends).

First-chance exceptions generally aren't a problem. "First-chance" means that it was caught internally. You might be seeing the signs of some completely unrelated internal thing.

I'm curious when you say "it won't let you F10 over string content". What do you mean it won't let you? Does it pop up an error dialog? does it fail to step to the next statement?

It might also help to put a try/catch/finally around the body your first method. Then at least you could set a breakpoint in the catch and finally blocks.

ljw1004
Jan 18, 2005

rum

gariig posted:

What is happening is the Task you are creating from the Task.Factory is starting to run and you are immediately returning null. You need to capture the Task<T> created from the Task.Factory and await it.

That won't work :) Task.Factory takes a void-returning delegate argument. Therefore it will treat the lambda as an "async void". Therefore the task returned from Task.Factory will be marked as completed at the moment the lambda hits its first await.

That's why you should use Task.Run instead. Task.Run takes a Task-returning delegate argument, and so it will treat the lambda as an "async Task", and so it'll be fine.

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

Thanks, that fixed the problems.

Also, don't use ".Result" in code that also uses await. It will usually run into the same problems.


Question: if you have a method that absolutely CAN'T be an async method for whatever reason, but it still needs to call an async method, how do you do this?

Answer: you basically can't. It has to be async all the way down and all the way up. More here: http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

ljw1004
Jan 18, 2005

rum

GrumpyDoctor posted:

I don't have any need for this right now, but I have a question about their example code:

Why would the same variable be captured on each iteration?

It's not captured on each iteration any longer. We made this change is VS2012. The temporary is no longer needed.

ljw1004
Jan 18, 2005

rum

Ithaqua posted:

I assume that's a C# 5 compiler thing, so it doesn't matter which framework version you're using, right?

Correct, it's a compiler thing and works on all target frameworks.


GrumpyDoctor posted:

Was the old behavior originally intended, or was it a bug? That behavior seems incredibly counterintuitive to me, especially because, if I understand right, there's no way to explicitly request it anywhere in the language. (Also, how did I not know that?)

The old behavior was just an oversight. The difference is only observable with lambdas. Prior to lambdas, there was no way to distinguish. When the compiler team added lambdas we just didn't even notice this one corner until it was too late.

ljw1004
Jan 18, 2005

rum

Newf posted:

I get that, but I don't get why I'm able to declare the type of a variable when the compiler doesn't know it ahead of time. It feels like a stricter version would force me to expect only objects from an IEnumerable and then cast them myself - at least in this case the cast becomes explicit.

Basically the C#/VB languages consider foreach loops to be explicit casts.

The relevant part of the C# spec is $8.4.4

quote:

A foreach statement of the form
code:
foreach (V v in x) embedded-statement
is then expanded to:
code:
{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}

The key bit is "(V)(T)e.Current".

ljw1004
Jan 18, 2005

rum

Bognar posted:

void UpdateAsync(IEnumerable<Delta<T>> deltas);

Curious why it's not Task-returning? With this signature you're basically telling callers of this interface "you're not allowed to know when the long-running operation has finished and you're not allowed to catch any exceptions that arise from it"...

ljw1004
Jan 18, 2005

rum

Newf posted:

The idea is to feed this to children, "do big data stuff" to gain information about the relative merits of different question/view schemes, feed a better refined diet of it to children, and so on.

I developed a similar kind of app over the past four years. Rather than asking maths questions, my app asks the kind of questions a psychiatrist would ask to discover if someone has the early stages of dementia. Like yours, we have multiple forms of questions, and we used big data to figure out the optimum questions. Actually we dynamically select the optimum question to ask next based on the responses that the patient has given so far.

I started with a complex codebase+model like yours, but abandoned it pretty quick. It makes me think you're going down the wrong path too. Here's why.


Big data statisticians can't do magic where you just throw the full complexity of the data at them and they somehow discern the truth. Instead they invent a model in their head, e.g. "the person has an innate intelligence X and an affinity for pictures Y, and each question has a pictureness A (standard deviation A2) and a difficulty B (standard deviation B2), and the distribution of scores for this question will be X*B + Y^2*A with standard deviation A2+B2". They partition the data into a training set which they use to solve a best-fit for X, Y, A, A2, B, B2, and a test set to see whether these numbers explain the rest of it.

Ultimately my statistician coded in "R". The model that I used to represent the data was nothing like the model he wanted to use to represent the data. He was the authority. He had the expertise to know exactly what sort of data cleanliness he needed, what he needed to store about it, and so on. I did the initial rough draft of the question classifications, but he was the one who made the authoritative model, and he was the one who had to.

So ultimately I ended up storing every single test as just a Dictionary<string,string>, i.e. an untyped map from question-code to answer. That's the way he coded it in R anyway. He came up with the authoritative question codes, and the authoritative way to code answers (e.g. blank = not yet answered, Y/N = yes/no, 1/2/3/... = numerical answer, D = void/doesn't-apply, ...)

He came up with the ontology, e.g.
code:
A question is either a multiple-choice question,
or a yes/no question,
or a date question,
or an unbounded integral numerical question,
or ...
He also came up with the question definitions e.g.
code:
Question code=WASHING,
         type=MULTIPLECHOICE,
         options={1,"no impariment",
                  2,"can wash self with assistance",
                  3,"needs complete assistance"}

Question code=FEEDING,
         type=MULTIPLECHOICE,
         options={1,"no impairment",
                  2,"if carer prepares meals, can feed self",
                  3,"needs carer to put food into mouth"}
Now we could and did express the question definitions in an XML file. There wasn't much point expressing the ontology in a data-driven format because we had to write so much code for it. And no point figuring out inheritance hierarchies because ultimately that's not what the data is about. He had to write code for intermediate calculations (e.g. "living-impairment = max(WASHING, COOKING, FEEDING"). I had to write code because each item in the ontology required its own viewmodel.


So my advice to you is this:

(1) Don't do any more coding until you've met with your data-scientist and he's done the first run through of data.

(2) Store your test in a Dictionary<string,string>. This will make it really easy to store and manipulate. Strong typing doesn't actually buy you anything in terms of bug-finding. Unit-tests on the data-analysis will do all that for you.

(3) Hand code your viewmodel and/or view for each different question type. You might use inheritance for your views, but it's not needed for your data or viewmodels.

(4) Remember localization!


Ultimately it just became a slog, having to code up fifteen different views. But I think that hand-crafted views for each question type are necessary to get a good user interface. I went through four complete rewrites of my views+viewmodels until I ended up with a way of doing it in XAML+code that felt clean.

ljw1004 fucked around with this message at 18:27 on Sep 28, 2014

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

Anyone know the equivalent of {StaticResource PhoneAccentBrush} for Windows 8 Metro apps? I want the theme accent color (so if you're on Windows 8, the same color as the volume bar when you set volume), which I figured out on the phone, but can't find the right value on Desktop.

I'm not sure what you're talking about, and I'm not aware of the concept even existing. When I change the volume in the system tray there are no colors. Can you give more examples of its use?

When you go to ControlPanel > AppearanceAndPersonalization > Personalization it shows "color". Is that it?

I notice that dialog boxes &c. in Metro apps appear to use the same color as the background color I chose at startup. Is that it?

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

That volume bar color changes when you change the accent color here:


I see. I asked your question on the internal WinRT mailing list and got back a definitive "no it's not possible for a modern app to retrieve the accent color".

ljw1004
Jan 18, 2005

rum

Knyteguy posted:

OK, well nothing that can be done then. Thanks for the help.

Apparently something can be done :) get a file without file-association, then GetThumbnailAsync(ThumbnailMode.DocumentsView), then get the pixel color at (1,1) - not at (0,0) because of the border. I'm not sure what kind of event you'd have to listen to in order to hear about changes.

ljw1004
Jan 18, 2005

rum

Scaramouche posted:

I think this is possible, but I was wondering if you guys could give me a direction to get started. I've got a large number of images provided by a third party. Some of them are either contrasty, adjusted poorly, or what have you. This means that backgrounds that should be white, are instead kind of an off-white.

I think you should do it all in Photoshop. Use Photoshop's "batch" functionality. There's no a-priori reason to think that an image-loading-and-processing library written in .NET will be faster than Photoshop. Indeed I'd expect Photoshop to be extremely highly optimized, native, GPU-accelerated. When you run Photoshop in batch mode it doesn't even render the images.

ljw1004
Jan 18, 2005

rum

Dirk Pitt posted:

Ahhh, I was using task.run to avoid having to make an async void.

What am I supposed to do if I need to await an asyncronous method in an override void or constructor? I typically make everything async all the way down. This is an issue I am curious about in a framework I have little control over (xamarin).

This is a common problem. It comes from frameworks that expect you to do stuff synchronously even though often you have to do it asynchronously. A typical scenario is that the framework has a void method "LoadSettings" or I guess your "LoadState", which it's willing to execute before the app's main page gets displayed. But obviously it'd be bad app design to DELAY the main page from being displayed while you're loading data off disk or off network.

So what you should do is kick off your async operation in LoadSettings or LoadState or wherever it is. Then return immediately so the outlines of the page can be shown to the user as soon as possible. Later on, you will be able to populate more data into the page once the load has finished.

I don't think you should be doing "Task.Wait" or "Task.Result" to block the main page from displaying until after the long-running load has finished...

code:
class C {
  overrides void LoadState() {
    loadStateTask = LoadStateAsync();
  }
  async Task LoadStateAsync() {
    ... await ...
  }
  Task loadStateTask;
}
After this you have to figure out how to deal with populating the page asynchronously after the data has loaded. There are a bunch of ways. In a XAML app I would write

code:
override async void OnNavigatedTo(...)
  await loadStateTask;
  ... populate the UI
}

ljw1004
Jan 18, 2005

rum

Gul Banana posted:

:[ we just got hit by a vb.net compiler bug. turns out that if you have a pair of iterator functions ... then it can be silently miscompiled as if you had written this:

Gosh! I implemented the iterator+async functions in VB for VS2012 and I never dreamt they could get this goofy. Sorry...


The Wizard of Poz posted:

Has anyone here tried using WP.NET (WordPress running under .NET)? The website makes it sound pretty good but they have virtually no concrete information on how it works or how to develop in C# for it or anything.

Also maybe consider http://www.orchardproject.net/ - I've heard lots of positive comments about it

ljw1004
Jan 18, 2005

rum
On two of the new features we're planning for C#6 and VB14, we've been rethinking about how they work. I'm posting here in case anyone has thoughts on the changes...

String interpolation - https://roslyn.codeplex.com/discussions/570292
This aims to be an easier way than String.Format to build up strings, including programmatic API strings like urls, filepaths, ...
code:
// Changed to use $"...{expr}..." rather than "...\{expr}...".
var x = $"hello {person.name} you are {person.age} years old"

// Changed to allow arbitrary format strings rather than just limited ones.
var x = $"you are {person.height:0.00} tall"

// Changed to allow access invariant culture.
IFormattable x = $"you are {person.height:0.00} tall";
var invstring = f1.ToString(null, CultureInfo.InvariantCulture);
NameOf operator - https://roslyn.codeplex.com/discussions/570551
This aims to be used in places like ArgumentNullException, or PropertyChangedEventArgs, or DependencyProperty.Register, where you need to pass the string name of a programmatic element but if your code is full of string literals then it's too easy to make mistakes.
code:
// Changed to allow certain expressions in its argument
Console.WriteLine(nameof(this.p)); // returns "p"

// Changed to disallow certain types
var s = nameof(List<>.Length); // now an error

// Changed to allow only a sequence of dot-qualified identifiers
var s = nameof(StrongBox<string>.Value.Length); // returns "Length"
var s = nameof(((StrongBox<string>)(null).Value); // error not allowed casts

ljw1004
Jan 18, 2005

rum

Mr Shiny Pants posted:

That is what I meant. I am used to instantiating classes and the like with C# before you can use them. F# will evaluate let bindings and instantiate stuff during program start. Just a different way of programming I guess.
At least for me, a different way of thinking about things.

That sounds kind of odd...

CLASSES
code:
class C {
  string s = System.DateTime.Now.ToString();
}

type C() = 
    let s = System.DateTime.Now.ToString()
Both are equivalent. In both cases, when you instantiate "C", then that instance of "C" makes the call to DateTime.Now.ToString(), and stores the value in an instance-specific field.



GLOBALS
code:
class Program {
   static string t = System.DateTime.Now.ToString();
}

let t = System.DateTime.Now.ToString();
Both are pretty much equivalent. F# has a built-in notion of global variables. The equivalent in C# is to put them inside classes. The F# code is executed at the moment it gets to the statement. The C# code is executed prior to the first time you mention the containing class in any way whatsoever.



It's good that you have a new way of thinking about program structure. Just be aware that this style of program structure is equally well achievable in both C#/VB and F#.

ljw1004
Jan 18, 2005

rum

GrumpyDoctor posted:

Here I am patiently waiting for a connection to my HttpListener: var conn = await httpListener.GetContextAsync();
But oh no! Somewhere else, someone is trying to shut the listener down! httpListener.Stop();
And the await throws an exception: A first chance exception of type 'System.Net.HttpListenerException' occurred in mscorlib.dll

What stupid thing am I doing?

I don't understand. What you wrote seems fine. What actually is the problem? Is it that you don't want someone to shut the listener down? (if so you'll have to figure out why the Stop routine is being called and no one here can help you...)

ljw1004
Jan 18, 2005

rum

GrumpyDoctor posted:

The reason I'm confused about this is that it seems like I can do what I want in F# (this code is not useful for anything other than illustrating what I don't get):
code:
    static member internal Start() =
        if Server.IsListening then () else
        listener.Start()
        let rec acceptConnections = async {
            let! connection =
                Async.AwaitTask <| listener.GetContextAsync()
            let! wsContext =
                Async.AwaitTask <| connection.AcceptWebSocketAsync("whatever", TimeSpan(0, 0, 15))
            webSocket <- Some(wsContext.WebSocket)
            return! acceptConnections }
        Async.Start acceptConnections
No exceptions are thrown if no connections are established. (At least, my attached debugger isn't seeing any.)

Is your debugger set to catch first-chance exceptions or merely unhandled exceptions? I've not used Async.Start, but from my reading of the docs it merely kicks off an async workflow without actually awaiting for the result. So it's possible that the F# code is getting the same exceptions but they're just being ignored...


The design you have (with a method called "Stop()") isn't great. Cancellation tokens are always better. That's me passing on the considered conclusion of a lot of async experts :)

Now it's true that there are a bunch of APIs which don't take cancellation tokens. That's a shame, but one that we can do something about. I wrote here
http://blogs.msdn.com/b/lucian/archive/2012/12/08/await-httpclient-getstringasync-and-cancellation.aspx
about another case very similar to yours - the HttpResponse.Content.ReadAsStringAsync() method doesn't accept a cancellation token, so you have to explicitly call a Stop method (actually in this case a Dispose method) and it throws an exception.


quote:

Again, I expected to be missing something major somewhere, but I did not expect that "Stopping an idle listener is considered exceptional" was it. Under that logic, every call to HttpListener.Stop() will throw an exception somewhere, right?

Note that in .NET the pattern is that cancellation throws an exception (OperationCancelledException). So please don't feel too squeamish about having cancellation exposed as an exception!

Some people will reasonably argue that "await httpListener.GetContextAsync()" should return NULL if the httpListener has already been stopped. Others will reasonably argue that it should throw an exception. Both behaviors will be fairly surprising the first time you see them but at least the exception is more informative!

ljw1004
Jan 18, 2005

rum

Mr Shiny Pants posted:

Thanks, much appreciated.

You should also be aware of CancellationTokenSource.CreateLinkedTokenSource


Scenario: you have one main CancellationTokenSource that is the one that will be fired when the user hits the Cancel button.

Then you want to start a subsidiary task with its own timeout. So you do
code:
void FooAsync(CancellationToken mainUserCancellation)
{
  var stopConcurrentTasks = new CancellationTokenSource();
  var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(mainUserCancellation, stopConcurrentTasks.Token);
  var attempt1 = httpClient.GetStringAsync(uri, linkedToken);
  var attempt2 = httpClient.GetStringAsync(uri, linkedToken);
  var attempt3 = httpClient.GetStringAsync(uri, linkedToken);
  var winner = await Task.WhenAll(attempt1, attempt2, attempt3);
  stopConcurrentTasks.Cancel();
}
That's because I want to cancel either if the user clicks the Cancel button, or if one of the other attempts at getting the string has completed quicker.

I might also have done
code:
stopConcurrentTasks.TimeoutAfter(1000)
to abandon all of them after 1 second.


Note: the difference between CancellationTokenSource and CancellationToken? the first is how you can send a request to cancel; the latter only has the power to listen for such requests.

ljw1004
Jan 18, 2005

rum

epalm posted:

How do you provide Documentation / User Guides to your clients via the .NET stack?

Entirely in MarkDown, on github. Allow anyone to submit pull-requests to improve the docs.

That's not how my team does docs, but it would be pretty awesome and agile and open.

ljw1004
Jan 18, 2005

rum
Plug:

We launched "VS2015 Preview" today: download

For .NET, it's going completely open source. The .NET team will do their development (checkins, bugs, ...) all in the open. If for whatever reason you wanted to package up your own tweaked version of System.Xml.dll with your app, say, you'll be able to do that.

For WPF, it has a solid roadmap for the future.

For VB/C#, here are complete lists of all new language features in C#6 and VB14.

Here in the VB/C#/.NET teams we're pretty excited! We'll writing more on the .NET blog, C# blog and VB blog, once we have time to write it in the coming weeks :)



EDIT: Got to mention the new VS2013 Community Edition. It's free, and a major step up from the "express" editions - kind of like the "Pro" version of VS, also allowing VS extensions. It's free for any non-enterprise application development.

ljw1004 fucked around with this message at 17:38 on Nov 12, 2014

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum

gariig posted:

Can I run this side-by-side with VS2013/2012 or should I stick it on a VM still?

Most of us in the VB/C# team are running it side-by-side with VS2013. It does install and uninstall cleanly.

I've heard two reports from people who said that they installed VS2015, and this prevented VS2013 from opening projects, but it was fixed when they uninstalled VS2015. Not sure what was going on.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply