2010-09-04 15 views
6

Lorsque vous déboguez, il est très utile de le faire:Comment imprimer un nom de variable et sa valeur sans taper deux fois le nom?

var = calc() 
print("var:", var) 

est-il une langue où cela est facile à faire? En C et C++, vous pouvez utiliser l'opérateur macro stringify # et Ruby j'ai trouvé cette question:

Ruby - print the variable name and then its value

La solution qui utilise un symbole: var et un bloc est ce que je veux.

En D, j'ai utilisé ceci:

void trace(alias msg)() { 
    writeln(msg.stringof ~ ":" ~ to!string(msg)); 
} 

Mais je ne suis pas sûr que c'est la meilleure façon, car il ne fonctionne que dans des cas simples. J'ai essayé plusieurs façons, mais parfois vous pouvez obtenir la chaîne, mais pas la valeur (parce que les variables sont hors de portée), ou vous devez d'abord mélanger le modèle, puis appeler la fonction.

Et les autres langues? Python? F#? Huer? Script Shell (quel shell)? Perl? (Je préfère rester loin de Perl, tho). Tcl? Lisp, Scheme? Java? (Il est hautement improbable que Java puisse le faire).

Même dans les langues où j'ai trouvé une sorte de solution, cela ne fonctionne que pour les cas simples. Que faire si je veux imprimer une expression arbitraire?

Si je devais concevoir une langue, cette fonctionnalité serait un must-have. :-)

Répondre

5

est ici très générale, mais un peu façon laide de le faire en D, en utilisant la compilation d'évaluation de la fonction temporelle (CTFE) pour générer le code comme une chaîne littérale, et une déclaration mixin pour l'évaluer:

import std.stdio, std.math; 

// CTFE function that generates trace code. 
string trace(string varName) { 
    return "writeln(\"" ~ varName ~ ": \", " ~ varName ~ ");"; 
} 

void main() { 
    // Trace a function call. 
    mixin(trace("sqrt(5)")); 

    // Trace a variable. 
    int foo = 5; 
    mixin(trace("foo")); 
} 

Les seuls problèmes sont que la saisie manuelle mixin est partout verbeux et tout ce que vous voulez tracer doit être dans un littéral de chaîne moche.

Notez qu'il existe deux types de mixins dans D. Modèle mixins sont mieux comportés à bien des égards, mais mixins à cordes (utilisés dans cet exemple) sont à peu près aussi général qu'il obtient, dans ce tout code peut, en principe, être généré via CTFE puis mélangé.

+0

Génial! C'est exactement ce dont j'avais besoin! Merci! La citation nécessaire est subtile, n'est-ce pas? Dommage que D ne permette pas d'interpoler varName pour le rendre plus propre. Cela ne me dérange pas de mettre l'expression dans une chaîne (je peux utiliser q {} pour avoir un jeton normal dans mon éditeur). En ce qui concerne la verbosité, je pourrais utiliser un nom de fonction très court :-) – marcus

2

Faible dans tout Lisp. Racket (née PLT Scheme):

(define-syntax-rule (debug-info expr) 
    (format "~a is ~a" (quote expr) expr)) 

(let ((long-boring-name 5)) 
    (display (debug-info long-boring-name))) 

# displays "long-boring-name is 5" 

(let ((fifty-two 52)) 
    (display (debug-info (+ fifty-two 6)))) 

# displays "(+ fifty-two 6) is 58" 
0

Je considère Tcl essentiellement "Lisp sans structures de données" (avec des chaînes au lieu de ... eh bien, à peu près tout, vraiment), il est donc presque aussi facile à Tcl comme en Lisp.

Il a été quelques années, mais je pense que quelque chose comme ça ferait l'affaire:

proc log_var {var} { 
    upvar 1 $var x 
    puts "$var is: $x" 
} 

set my_var 5 
log_var my_var 

Je pense qu'il ya probablement un moyen d'utiliser uplevel d'étendre ce travail à des expressions arbitraires.

+0

Je ne l'avais jamais programmé en Tcl avant (je l'ai fait connaître la syntaxe de base de la langue), mais après votre suggestion que je suis venu avec ceci: proc log_expr {exp} { ensemble x [uplevel 1 $ exp] BREAK_LINE_HERE met "$ exp est: $ x" } log_expr {expr 1 + 1} CECI EST IMPRESSIONNANT !!!! – marcus