Question

Quel est le hack de métaprogrammation le plus cool plutôt pratique que vous ayez fait ou que vous avez vu faire dans le langage de programmation D? Un peu pratique signifie par exemple d’exclure le traceur de rayons au moment de la compilation.

Était-ce utile?

La solution

Pour ce qui est du plus cool, je dirais que PyD de Kirk McDonald (et d’autres liaisons similaires) comme celles-ci ont nécessité beaucoup de travail de détection et de traitement de nombreux types différents, ainsi que de génération de code complexe.

Cela dit, PyD ne gagne que parce que BLADE utilise techniquement le CTFE, pas les modèles.

Sur une note plus personnelle, les modèles D ont été largement utilisés dans un de mes projets de recherche. C'est un framework de simulation où les modules peuvent définir leurs propres types de données privées. L’exposition d’un nouveau type d’utilisateur au cadre nécessite une seule ligne de code qui crée un analyseur XML pour le type ainsi que le code de sérialisation / désérialisation réseau associé.

Autres conseils

Un type de précision arbitraire Il génère du code ASM au moment de la compilation (avant la le compilateur fait)

DParse dans les outils Scrapple est un générateur d’analyseur basé sur un modèle. Cependant, ldc est le seul compilateur D avec un GC fonctionnant à la compilation (mais même dans ce cas, il a quelques crashs étrangement aléatoires). J'ai un peu joué avec elle et vous pouvez faire des choses intéressantes comme l'analyse de fichier de configuration, etc., mais jusqu'à ce que la compilation soit terminée, GC ne puisse pas faire grand chose.

Le pont D / Objective-C utilise des modèles pour vous permettre de manipuler des objets Cocoa. en D.

Mes favoris seraient ElemType et KeyType de tools.base:

template ElemType(T) {
  alias typeof((function() {
    foreach (elem; Init!(T)) return elem; assert(false);
  })()) ElemType;
}

template KeyType(T) {
  alias typeof((function() {
    foreach (key, elem; Init!(T)) return key; assert(false);
  })()) KeyType;
}

Une structure du modèle de type uni (elle ne vous permet pas de créer erreurs unitaires.)

Compiler le hachage de la chaîne de temps . Vous pouvez l'utiliser pour masquer les chaînes incorporées dans votre code. Il suffit de rechercher "hash". plusieurs autres exemples intéressants sur cette page, aussi.

Un exemple est la fonctionnalité bitfields dans la bibliothèque standard de D qui génère du code pour la manipulation de champs de bits à partir d'une mise en page spécifiée par l'utilisateur.

La fonctionnalité Tuple est un autre exemple. Il génère un tuple basé sur les types fournis par l'utilisateur et les noms facultatifs. Il n’ya pas beaucoup de umph génératif ici sauf pour l’injection des champs nommés, mais je pense que c’est un exemple illustratif.

Sans connaître l'exploit de Lambert, je viens d'ajouter memoize à la bibliothèque standard - voir ici pour la documentation, ici pour le code et ici pour le groupe de discussion associé discussion.

Une autre fonctionnalité sur laquelle j'ai travaillé est une fonction d'ordre supérieur qui tabule une fonction intégrale ou à valeur réelle (par exemple, offre une exponentielle rapide). Ce n'est pas encore prêt pour la publication.

Une fois que la création d'objet sera autorisée lors de la compilation, il sera facile de créer par exemple. Les moteurs d’expression régulière qui font toute la génération des automates lors de la compilation.

Je vais répondre à ma propre question car celle-ci n’existait pas lorsque je l’ai posée. J'ai écrit un correctif dans le ramasse-miettes qui utilise des modèles et une introspection lors de la compilation pour générer les informations de décalage du pointeur pour des types définis arbitrairement complexes par l'utilisateur afin de permettre une analyse de tas précise, au lieu de le faire dans le compilateur.

J'ai écrit une fonction memoize () dont l'en-tête est ceci (le code est un peu long pour coller ici):

auto memoize (TFunc) (TFunc func);

Vous lui donnez l'adresse d'une fonction et renvoie un délégué fortement typé (même signature et type de retour que la fonction d'origine) qui met en cache les valeurs de retour de la fonction d'origine, afin de l'appeler deux fois avec le même paramètre appelle la fonction sous-jacente qu'une seule fois. Par exemple, voici un fichier mémoized, "récursif". définition de la séquence de Fibonacci qui s’exécute en temps linéaire plutôt qu’exponentielle:

uint fib (uint n) {retourne n > 0? n > 1 ? memoize (& fib) (n - 1) + memoize (& fib) (n - 2): 1: 0; }

Vous pouvez l'appeler normalement, comme dans: fib (1000);

Modifier: le code précédent dont le lien que j'avais posté était plutôt hideux; cette version est beaucoup plus élégante .

Mixins pour lire et écrire des structures simples à partir d'un objet Stream :

template TStructReader() {
        private alias typeof(*this) T;
        static T opCall(Stream stream) {
                assert(stream.readable);
                T ret; stream.readExact(&ret, T.sizeof);
                return ret;
        }
}

template TStructWriter() {
        private alias typeof(*this) T;
        void write(Stream stream) {
                assert(stream.writeable);
                stream.writeExact(this, T.sizeof);
        }
}

Utilisez-le comme ceci:

align (1) struct MyStruct {
        ... definitions here ...
        mixin TStructReader;
        mixin TStructWriter;
}

auto ms = MyStruct(stream);
ms.write(stream);

LuaD utilise également largement la métaprogrammation pour interagir de manière transparente avec Lua. Vous pouvez enregistrer une classe entière avec une seule commande.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top