Nov 7, 2022

Une petit casse-têtes C# 10 - La solution - (Part II)

Leia este post em português

Read this post in English.

Dans mon dernier post j'ai lancé un défi pour modifier le contenu imprimé par le programme ci-dessous afin qu'il n'affiche que les lignes comprenant des nombres impairs.

La seule mise en garde est que j'ai limité ce qui pourrait être modifié comme suit:

  1. Vous ne pourrez pas modifier que le type du paramètre msg du méthode Foo.
  2. Vous ne pourrez pas modifier l’implémentation du loop for.
  3. Vous ne pourrez pas utiliser IL post-processing (mais ça serait une exercice intéressant 😃)
  4. Toutes les autres modifications dans le de code sont valides.

J'ai également dit que si vous regardiez attentivement dans le code, vous seriez en mesure de trouver des indices sur la direction de la solution basée sur des morceaux de code qui n'étaient pas essentiels. J'y reviendrai plus tard, mais permettez-moi d'abord de vous présenter rapidement une fonctionnalité C# qui existe depuis C# 6 et qui sera utilisée dans ma solution finale : Interpolated strings.

Ce sont des littéraux de chaînes préfixés par le caractère $ et contenant des expressions C# entourées d'accolades ({ ... }) pour lesquelles le compilateur C# émettra du code pour remplacer ces expressions par leurs valeurs respectives ; l'idée principale est de simplifier le code de formatage des chaînes. Par exemple, dans le programme ci-dessous:

Le compilateur C# remplacera {i} par la valeur de la variable i et {args[i]} par la valeur du élément à l'index i du array args.

Lorsque la prise en charge des chaînes interpolées a été introduite pour la première fois, le compilateur émettait un code similaire à:

Ou, en d'autres termes, il remplacerait la interpolated string par un ou plusieurs appels à String.Format() (comme indiqué à la ligne 10 ci-dessus). Il n'y a rien de mal à cela, après tout, c'est presque exactement le code qu'un développeur écrirait en l'absence de prise en charge de cet fonctionnalité, mais avec la poussée des performances ces dernières années, les développeurs .NET ont réalisé qu'il y avait une marge d'amélioration dans ce domaine; en effet, si vous examinez le code ci-dessus, il existe quelques codes non idéaux, en termes de mémoire:

  1. à ligne #5, il y a une allocation de un array.
  2. il y a 3 opérations de boxing (lignes #6, 7 & 8)
  3. La méthode String.Format() method finira probablement par appeler Int32.ToString() qui allouera une nouvelle string (au moins sur certaines versions de .NET).

Dans les petits programmes (ou même moyens?) cela ne ferait aucune différence, mais sur les applications plus grandes, ou les applications qu'utilisant fortement la manipulation de strings, cela s'est avéré être une source potentielle de problèmes de performances, donc en C # 10, le concept de string interpolation handlers, le sujet du prochain post, a été introduit pour aborder certains d'entre eux.

Have fun!

Adriano

A small C# 10 programming puzzle - Answer (Part II)

Leia este post em português

Lire cet post en Français.

In the last post I've posed a challenge to change the output of the following program to show only lines with even numbers.

The only caveat is that I've restricted what could be changed as follow:

  1. You could not  change Foo's  implementation in any way other than changing its msg parameter type.
  2. You could not change the implementation of the for loop in any ways.
  3. You could not on IL post-processing in any way (but it would be a nice exercise 😃)
  4. Any other changes to the source are acceptable

I've also said that if you look carefully in the code you would be able to find some clues on the direction of the solution (at least the one I was thinking about) based on pieces of code that were non essential. I'll come back to those later but first let me quickly introduce a C# feature that has been around since C# 6 that will be used in my final solution: Interpolated strings.

Interpolated strings are strings literals prefixed with $ character and containing C# expressions wrapped in braces ({ ... }) for which C# compiler will emit code to replace such expressions with their respective values; the main idea is to simplify string formatting code. For example, in the program below:

C# compiler will replace {i} with the value of variable i and {args[i]} with the value of the element at index i of the args array.

When the support for interpolated strings was first introduced the compiler would emit code similar to:

Or, in other words, it would replace the interpolated string with one or more calls to String.Format()(as show in line #10 above). There's nothing wrong with that, after all, that is almost exactly the code a developer would write in the absence of interpolated string support, but with the push for performance in the recent years, the .NET developers realized that there was some margin for improvements in that area; indeed, if you look into the code above, there are a couple of non-ideal code, memory wise:

  1. In line #5, there's an array allocation.
  2. There are 3 boxing operations (lines #6, 7 & 8)
  3. String.Format() method will likely end up calling Int32.ToString() which will allocate a new string (at least on some versions of .NET).
In small (or even medium ?) programs that would barely make any difference, but on bigger applications making heavily use of string manipulation that proved to be a potential source of performance issues so in C# 10 the concept of string interpolation handlers, the subject of the next post, was introduced to address some of those.

Have fun!

Adriano

Um pequeno puzzle sobre o C# 10 - Solução (Parte II)

Read this post in English

Lire cet post en Français.

Em meu último post apresentei um desafio para modificar a saída do programa abaixo de forma que o mesmo apresentasse apenas as linhas contendo números pares.

As únicas restrições  eram que você:

  1. Não poderia modificar a implementação do método Foo, a não ser, o tipo do parâmetro msg.
  2. Não poderia modificar a implementação do laço for.
  3. Não poderia utilizar IL post-processing
  4. Quaisquer outras modificações seriam aceitas.

Eu também mencionei que ao observar atentamente o programa serial possível encontrar pistas da solução que eu estava pensando na forma de código que não era essencial para que o programa apresentado compilasse/funcionasse; obviamente eu vou discutir estes pontos, mas antes, gostaria de apresentar a funcionalidade base (introduzida no C# 6) a qual será usada na minha solução: Interpolated strings.

Interpolated strings tem como objetivo simplificar o código de formatação de strings sendo formadas por strings literais prefixadas com o caractere $ e que contem expressões C# envolvidas em chaves ({ ... }) as quais são substituídas pelos seus respectivos valores pelo compilador C#. Por exemplo, no programa abaixo:

O compilador C# substituirá {i} pelo valor da variável i e {args[i]} pelo valor do elemento armazenado no índice i do array args.

Até a versão 9 do C#, o código acima seria convertido pelo compilador para algo como:

Ou, em outras palavras, o compilador substituiria a interpolated string com uma ou mais chamadas ao método String.Format()(como observado na linha #10 acima). Ainda que este  código não seja essencialmente incorreto (afinal de contas este seria mais ou menos o código usado na ausência desta funcionalidade), com a crescente busca na melhoria de performance no últimos anos, os desenvolvedores .NET notaram que existia margem para melhorias nesta área; e realmente, se observarmos atentamente notaremos claramente alguns padrões, não ideais, com relação à utilização de memória:

  1. Na linha #5, há uma alocação de um array.
  2. Existem 3 operações de boxing (lines #6, 7 & 8)(ou seja, alocações no heap)
  3. O método String.Format() muito provavelmente executará o método Int32.ToString() o qual acabará introduzindo alocações de strings no heap.

Note que, em programas pequenos (ou talvez mesmo em médios ?) estas alocações  seriam praticamente desprezíveis; contudo em aplicações maiores ou aplicações que fazem uso constante de tais operações estas alocações podem introduzir problemas de performance devido ao mecanismo de Garbage Collection (ou GC) necessitar executar constantemente.

Com o objetivo de melhorar a performance de tais aplicativos, C# 10 introduziu o conceito que abordaremos no próximo post e que será usado na solução do problema proposto: string interpolation handlers.

Have fun!

Adriano