Oct 24, 2018

Éprouver en ligne C# compilateurs

Read this post in english

Leia este post em português

Salut

Je voulais remercier tout ceux qui m'ont aidé avec la correction de ce texte (sans ordre particulier): David Geoffroy, Charles Beauchemin, Jean-Philippe Leroux

Si vous travaillez avec C#, il est probable que, comme moi, vous finissiez par créer plusieurs projets seulement pour tester le comportement de certains extraits de code. Si c'est votre cas, je vous recommande d’utiliser un compilateur C# enligne, un site Web où vous pouvez taper un extrait de code C# et ce site compilera / exécutera le code. C’est un outil inestimable pour tester vos hypothèses sur le code très rapidement.

Entre autres, j’aime  sharplab.io, lequel, en plus de vous permettre jouer avec code C#, a aussi un ensemble de fonctionnalités intéressantes, que je vais décrire ci-dessous.

Sélection Branche / Fonctionnalité

Si vous suivez le développement du langage C# (ce que vous devriez faire), cette fonctionnalité est vraiment utile; cela vous permet de choisir quelle version du compilateur à utiliser (de plusieurs feature branches), ou entre autres, vous pouvez expérimenter diverses fonctionnalités en sélectionnant quel compilateur utiliser.

Afficher compilateur arbre de syntaxe (Syntax Trees)

Ceci ressemble à la fenêtre Roslyn Syntax Visualizer dans Visual Studio (vous avez besoin d'installer .NET Compiler Platform SDK dans Visual Studio pour que cette fenêtre devient disponible). Cette fonctionnalité est très utile pour tester la nouvelle syntaxe C#.

Afficher IL généré

C’est la sorte de fonctionnalité que la plupart des  développeurs C# n’ont jamais besoin, mais pour ceux qui en ont réellement besoin, elle est vraiment utile. Est-que vous voulez regarder comment un extrait de C# code est traduit pour IL? Simplement écrire le code et choisir IL dans le dropbox et voilà.

Afficher JITed/code ASM généré

Si la dernière fonctionnalité n’est pas pour plusieurs de développeurs C#, elle est encore plus limitée, mais elle peut vraiment aider les développeurs qui besoin de comprendre comment un extrait de C# code est traduit pour le langage machine (ASM).

Voilà!.

Amusez-vous bien!

Adriano

Oct 20, 2018

Avoiding hidden data copies in C#

Lire ce post en Francais

Leia este post em Português

Given the following code, Can you spot any issues? Hint: there's at least one, related to value types & performance!

Ok, lets make it a little bit more obvious by changing it to be a logical error instead of only a performance issue (the problem would be easly found if we had unit tests in place). Now what would be the expected output of the following code? 

If you answered:
M() : 0
M() : 1
M() : 2
you will be surprised to see:
M() : 0
M() : 0
M() : 0

and now it should be clear that something is not right.

The problem is that the field s has been declared as readonly which caused the compiler to make a defensive copy before each s.M() invocation (the compiler does not perform flow analysis to prove the invoked method will not violate the readonly invariant); this means that M() is increasing counter on a temporary value each time it is called leaving s.counter alone. 

Notice that in the first version of the code which don't rely on the struct to be mutable (which is good, since you should avoid mutable value types) it is not easy to realize something is not quite right. Even with the later version it is not clear why counter never gets incremented. 

To understand that lets look in at the IL for the Main() method (you can also use sharplab.io to play with the code) :
You can observe the copy happening at IL offsets IL_0001 (ldsfld valuetype S C::s) & IL_0006 (stloc.0) then again at offset IL_000f & IL_0014 and finally at offsets IL_001d & IL_0022. Notice that after copying s to the local variable at slot 0 (zero) the address of this local variable is loaded into the stack and  M() method is invoked.

Unfortunately C# language provide other opportunities to play tricks like this on us; I can think of at least 2 cases: in parameters and local ref readonly variables. See the example below:
So how can you avoid such hidden copies? The answer depends which version of C# you are targeting:
  • < 7.3: The only way to get rid of those copies (AFAIK) is to remove readonly modifier from the field (s in this example)
  • >= 7.3:  in this case you can declare your struct as readonly so the compiler will enforce this invariant (and emit an error if you try to mutate any of the struct's state).
One question that you may have now is: how bad are those  extra copy operations? IMO it depends on whether they affect your program performance (i) and/or behavior (ii) and your requirements. In the case that the behavior of the program is affected I think it is a consensus that those copies need to go whereas in the case in which performance is affected it is debatable whether one should invest time/effort to chase/fix those (of course, you always should have a performance goal). That being said, if you use Visual Studio for development you can install ErrorProne.NET which will pinpoint this type of issues.

Last but not least, if you are interested in deep content about .Net I recommend you to follow this blog

Adriano