Travailler avec les clôtures lexicales
dans Powershell (1/2)

Certaines procédures inscrites au cœur de la création d'un jeu vidéo suggèrent souvent l'utilisation de langages de script. Qu'il s'agisse d'aménager un processus de compilation ou plus simplement de générer des Assets, ces langages apparaissent définitivement utiles.

Dans cette perspective, une approche intéressante (que d'aucuns qualifieront peut-être de marginale) consiste à se tourner vers Powershell, une solution développée et éditée par Microsoft. Construit par dessus l'écosystème .net, Powershell repose sur une bibliothèque riche en fonctionnalités. Il est bien entendu laissé à l'appréciation du développeur de le substituer à d'autres outils plus conventionnels tels que Node.Js ou Python.

Généralement comprise dans la boite à outils du développeur, la clôture lexicale (ou en anglais : function closure) est une technique à tonalité fonctionnelle souvent impliquée dans des pratiques de programmation originales. Transposer cette technique vers Powershell n'est cependant pas trivial et va demander une certaine gymnastique pour y parvenir. Une projection simple consiste à imaginer le code Javascript suivant:

/* Javascript */
const $foo = (($bar) => ($bar = 23, () => ++$bar))();
$foo(); // retourne «24»
$foo(); // retourne «25»

Dans l'exemple ci-dessus, la variable $bar est persistante mais confinée à sa clôture. Isolée du reste du code, elle offre au programmeur une manière sécuritaire de travailler avec les valeurs. Dans un langage à portée lexicale (ou statique), comme c'est le cas en Javascript, le cadre d'utilisation d'une variable est délimité par un point d'entrée et un point de sortie qui sont spontanément visibles dans le code. Une tentative inspirée mais erronée de transposer vers Powershell pourrait s'imaginer de la façon suivante:

<# Powershell #>
$foo = & { [int32]$bar = 23; Return { (++$global:bar) } }
& $foo # retourne «1»
& $foo # retourne «2»

Les appels successifs à $foo retournent ici un résultat différent. La variable $bar, d'abord initialisée avec la valeur 23, n'est plus visible lors de l'appel au bloc d'instructions $foo qui contient le sous-ensemble { (++$global:bar) }. Une situation naturelle pour Powershell qui agit de manière à propager l'environnement sur la pile d'appels conformément à la notion de portée dynamique. Cette mécanique réduit la disponibilité de $bar à la chaîne d'exécution dans laquelle elle apparait et l'appelant à $foo n'en fait pas partie dans l'exemple. Une représentation simple de la notion de portée dynamique en Powershell est illustrée ci-dessous:

<# Powershell et portée dynamique de variable #>
$foo = { ('«',$bar,'»' -join '') | Out-Host }
& { $bar = 'Hello'; & $foo } # «Hello»
& { $bar = 'World'; & $foo } # «World»

Cette manière de composer, sans doute peu ordinaire, présente des perspectives de conception intéressantes lors d'un développement. Point d'ancrage utile qui permet de se diriger, à l'occasion du prochain billet, vers une mise en œuvre concrète de la clôture au sein du langage.