# The "problem"

Define a function log (or other 3 letter name) which when called will log/print/write (whatever is the default for the language in question) both the instruction (as source) and the first argument. In other words:

i=777
j=333
log(i) //outputs: "log(i) 777"
log(i+j+1) //outputs: "log(i+j+1) 1111"


For all practical purposes the output i: 777 would be enough, but in some languages there are very specific reflection libraries for that, and that would be no challenge, so the entire instruction should be outputted.

# Inspiration

The inspiration for this was me and another programmer discussing how irritating it is that often (with bad debuggers), you write things like console.log("i:", i), next we made a (pretty crazy) javascript (node only) solution (it outputs i: 777 rather than the entire line of source) which was suprisingly long and reminded me of codegolfing and made me wonder how much better other (especially code golfing) languages would fare.

# Bonuses

-10%: No file reading (beyond the compiler)

PS. This is my first 'question' here, so feel free to point out any mistakes I made.

• Welcome to CodeGolf.SE! I personally think your question is pretty decent, but it's usually a better idea to run question ideas through the sandbox to resolve ambiguities etc before people start working on answers. – Martin Ender Mar 21 '14 at 18:25
• Thx and useful@sandbox, might be good to explain it's use on help/on-topic (it's mentioned, but I didn't consider it worth checking the way it was described there). – David Mulder Mar 21 '14 at 18:36
• @WolleVanillebärLutz: Of course it's not, did you see anyone claim that to be true then? – David Mulder Mar 27 '14 at 20:45
• The bounty is for TrungDQ (I think his solution is amazing just from a code perspective (better than our node only solution), regardless of length), have to wait 24 hours though before I can award it. – David Mulder Jun 8 '14 at 15:53

# C (40 -10% = 36) (38 -10% = 34.2)

Note that, in C, a log function can only be defined for a specific type. Therefore, this log "function" takes only int arguments.

#define log(x)printf("log("#x") %d",x)


A more general solution specifies how to print the argument, in addition to the argument itself:

#define lg2(f,x)printf("lg2("#x") "f,x)


which would be used as e.g. lg2("%s", "I'm a string"); or lg2("%f", 3.1415).

• I don't think the final brackets around x are necessary. – user12205 Mar 21 '14 at 19:07
• @ace: I thought they might be needed if the user puts in some odd characters in the argument, but upon reflection I think you're right. I'll remove them. – nneonneo Mar 21 '14 at 19:09

# Python (65 -10% = 58.5)

This assumes your code is in a file (it produces odd output if invoked in the interactive interpreter):

import traceback as t
def log(x):print t.extract_stack()[-2][3],x


It has been tested on Python 2.7.6.

Example:

def foo():
x = 1
log(x)
for i in xrange(10):
log(x+i+1)
return x

log(foo())


outputs

log(x) 1
log(x+i+1) 2
log(x+i+1) 3
log(x+i+1) 4
log(x+i+1) 5
log(x+i+1) 6
log(x+i+1) 7
log(x+i+1) 8
log(x+i+1) 9
log(x+i+1) 10
log(x+i+1) 11
log(foo()) 1

• Nice! Got to say, this is the kind of crazy stuff that interests me as a programmer (negative index on a native function :O ) :P wonders off to find some docs – David Mulder Mar 21 '14 at 19:16

# C++ 12171 67 -10% = 60.3

#include<iostream>
#define log(x)std::cout<<"log("#x") "<<(x)<<"\n"


Used like this:

int main() {
int i = 777;
int j = 333;
log(i);
log(i+j+1);
}


Outputs:

log(i) 777
log(i+j+1) 1111

• You can remove 30 char and make a one-liner if you write it in C instead of C++: #define log(x)printf("log(%s) %d\n",#x,x), but that will only work of integers. – user12205 Mar 21 '14 at 19:02
• @ace: then it only works for one type. (Also, this is the solution I proposed, see below) – nneonneo Mar 21 '14 at 19:02
• @nneonneo I hate it when I forgot to refresh before posting a comment. – user12205 Mar 21 '14 at 19:05

# Rebol3 - 31.5 (35 - 10 %)

Here is a simple implementation shortened from @draegtun that works well for numbers:

log: func[p][print[{log[}p{]}do p]]


Running it outputs:

>> log: func[p][print[{log[}p{]}do p]]
>> i: 777
>> j: 333
>> log [i]
log[ 777 ] 777
>> log[i + j + 1]
log[ i + j + 1 ] 1111


It can be much more flexible (for displaying the form of non-number types) at 42.3 chars (47 - 10%)

log: func[p][print[{log}mold p mold/only do p]]


The output:

>> log: func[p] [print[{log}mold p mold/only do p]]
>> log [join "4" 4]
log [join "4" 4] "44"  ;; shows a string
>> log [1 + 2]
log [1 + 2] 3


# Javascript (325)

I think this is the log function you are looking for:

function log(m){L=(new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];N=L.split(':')[1];C=parseInt(L.split(':')[2]);R=new XMLHttpRequest();R.open('GET',location.href,0);R.onload=function(){console.log(R.response.split('\n')[N-1].substr(C-1).split(';')[0]+' = '+m)};R.send()}


# Usage

<script>
function log(m){L=(new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];N=L.split(':')[1];C=parseInt(L.split(':')[2]);R=new XMLHttpRequest();R.open('GET',location.href,0);R.onload=function(){console.log(R.response.split('\n')[N-1].substr(C-1).split(';')[0]+' = '+m)};R.send()}

function doSomething() {
var a = 123; log(a); var b = "Hello, I am TrungDQ!"; log(b);
}
doSomething();
var message = "...or just do it out here";
log(message + "!");
</script>


## Output

log(a) = 123
log(b) = Hello, I am TrungDQ!
log(message + "!") = ...or just do it out here!


## Long code

<script>
function log(msg) {
// Get the line number and offset of the line where is function is called
var lineInfo = (new Error()).stack.match(/(at log \([\s\S]+?at .+?:)\d+:\d+/m)[0].split('\n')[1].match(/:\d+:\d+/)[0];
var lineNum = lineInfo.split(':')[1];
var charOffset = parseInt(lineInfo.split(':')[2]);

// Get the file source
request = new XMLHttpRequest();
request.open('GET', window.location.href, true);

// Get file source code
var response = request.responseText;
// Get the log line
var line = response.split('\n')[lineNum - 1];
// Get the log statement
var logStatement = line.substr(charOffset - 1).split(';')[0];
// Print it
console.log(logStatement + ' = ' + msg);
};
request.send();
}

function doSomething() {
var a = 123; log(a); var b = "Hello, I am TrungDQ!"; log(b);
}
doSomething();
</script>


Only works when the script is put inside <script> tag which is put in .html document because it sends a request to location.href to get the source code. JSfiddle, F12 Dev Tool Console, embbed .js files won't work, I am trying to make it available everywhere...

Anyway, this question is interesting.

• I'm little skeptical this is cross browsers. – Farid Nouri Neshat Mar 23 '14 at 12:27

# Scala - (221 - 10%) = 198.9

Yay macros! This is actually exactly the type of stuff they're for.

import language.experimental.macros
def log(p:Any)=macro l
def l(c:reflect.macros.Context)(p:c.Expr[Any])={import c.universe._;reify{println("log("+(c.Expr[String](Literal(Constant(show(p.tree)))).splice)+") "+p.splice)}}


import language.experimental.macros
def log(p: Any) = macro l
def l(c: reflect.macros.Context)(p: c.Expr[Any]) = {
import c.universe._
val inputString = show(p.tree)
val inputStringExpr = c.Expr[String](Literal(Constant(inputString)))
reify {
println("log(" + (inputStringExpr.splice) + ") " + p.splice)
}
}


Example:

log(1)
val x = 3
log(x)
val y = 4
log(x+y)


Outputs:

log(1) 1
log(x) 3
log(x.+(y)) 7


Since addition is a method call in Scala, it adds that verbose syntax back in, but it's pretty close! It's also a bit more verbose in a couple of other cases.

• Wow, that's quite interesting to see@the addition of the function. So much cool stuff to learn :D – David Mulder Mar 21 '14 at 23:46

# bash (21 - 10% = 18.9)

This:

alias log=echo;set -v


Then use log like you would use echo:

log $((1+1))  or A=2 B=3 log$((A+B))


This method will do all what is required; as a bonus, some extra information will also be printed, but no explicit rule forbid it.

# BASH

Arguments are not passed using "(...)" in BASH, so I let the output of 'log()' fit that style:

$log(){ echo "$FUNCNAME $@:$(($@))"; }$ i=333
$j=777$ log i
log i: 333
$log i+j+1 log i+j+1: 1111  • $((...)) can be $[...] instead but I did not count the chars, so it doesn't matter up to now. – user19214 Jun 8 '14 at 16:28 # Clojure (defmacro log[x] (let [x# ~x] (println "log("'~x")" x#)))  Homoiconicity has its benefits! To use: (def i 777) (def j 333) (log i) ;Prints log( i ) 777 (log (+ i j 1)) ;Prints log( (+ i j 1) ) 1111  Let's see what's happening with macroexpand: (macroexpand '(log (+ i j 1))) ;; Prints the following: (let* [x__1__auto__ (+ i j 1)] (clojure.core/println "log(" (quote (+ i j 1)) ")" x__1__auto__))  • If you quote x, do you really need to use an intermediate gensym (ie. x#)? I think you will only evaluate the expression once (btw, I am no Clojure expert) – coredump Nov 2 '14 at 14:40 # Julia, 51*0.9=45.9 julia> x=4 4 julia> macro log(x) println("log($x) $(log(eval(x)))") end julia> @log(x) log(x) 1.3862943611198906  Alternatively, but not meeting the rules julia> @show log(x) log(x) => 1.3862943611198906  ## Tcl, 42.3 (47 - 10%) proc log c {puts [dict g [info fr -1] cmd]\$c}


Usage:

set i 777
set j 333
log $i ;#outputs: "log$i 777"
log [expr {$i+$j+1}] ;#outputs: "log [expr {$i+$j+1}] 1111"


Edit: small improvement

# Common Lisp - 119.7 (133 -10%)

(defmacro @(&whole f &rest r)(let((g(gensym)))(let((,g(multiple-value-list,@r)))(progn(format t"~s~{ ~a~}
"',f,g)(values-list,g)))))

• Named @ because log is the standard logarithm function and locked by default (at least on SBCL). Also, @ is only one character long.
• Acts as a progn, taking a variable number of arguments, but prints to standard output. In real applications, I would probably signal a condition with an S-expression instead of printing space-separated output.
• Contrary to the existing Clojure solution, we ultimately returns the value of the logged expression, so that (@ x) can be used whenever x is used.
• Printing uses prin1, which outputs a read-able string. This is useful when trying to reproduce logged expressions.
• Handles all possible types (see C answer)
• Takes into account mutliple values
• Does not produce different outputs (see Scala answer)
• Works from a file and from REPL (See Pyhton answer)
• Does not require browser/interpreter trick (Python traceback, Javascript request)

# Sample outputs:

CL-USER>(@ (+ 3 2))   ; user input
(@ (+ 3 2)) 5         ; printed output
5                     ; result of expression

CL-USER> (@ (values 3 4))  ; input
(@ (VALUES 3 4)) 3 4       ; logging
3                          ; first value
4                          ; second value

CL-USER>(@ (round 3.4))
(@ (ROUND 3.4)) 3 0.4000001
3                          ; rounded value
0.4000001                  ; delta


And finally, if I log the above defmacro, I have the ungolfed version:

CL-USER> (@ (defmacro @(&whole f &rest r)(let((g(gensym)))(let((,g(multiple-value-list,@r)))(progn(format t"~s~{ ~a~}
"',f,g)(values-list,g))))))
STYLE-WARNING: redefining COMMON-LISP-USER::@ in DEFMACRO
(@
(DEFMACRO @ (&WHOLE F &REST R)
(LET ((G (GENSYM)))
(LET ((,G (MULTIPLE-VALUE-LIST ,@R)))
(PROGN
(FORMAT T ,"~s~{ ~a~}
"
',F ,G)
(VALUES-LIST ,G)))))) @
@ ; actual result


# PHP 138

You can't redeclare log in PHP without using another module (APD) so I used logg instead, i can resubmit with log example if needed. That's minor, but more sinful i guess is that this assume the log function is on a line by itself. I can update my answer as dictated by comments.

<?php function logg($v){$b=debug_backtrace()[0];$h=fopen($b['file'],"r");for($i=0;$i<$b['line']&&$l=fgets($h);$i++);echo trim($l)."$v";}


example output:

for ($i=1;$i<10; $i++) {$j=$i+1;$k=$j+1; logg($i+$j+$k);
echo "\n";
}
/*
logg($i+$j+$k); 6 logg($i+$j+$k); 9
logg($i+$j+$k); 12 logg($i+$j+$k); 15
logg($i+$j+$k); 18 logg($i+$j+$k); 21
logg($i+$j+$k); 24 logg($i+$j+$k); 27
logg($i+$j+\$k); 30
*/


# JavaScript 55 53

function log(x){console.log('log("'+x+'") '+eval(x))}


Usage:

var i = 777,
j = 333;
log("i")
log("j")
log("12*4")
log("i*j-4")


Output:

log("i") 777
log("j") 333
log("12*4") 48
log("i*j-4") 258737


You MUST use double quotes " otherwise it will not work.

• Regardless of it already bending the rules by not following the example pseudo code I provided, the bigger problem is that it only works if and only if the variables are defined in the global context (I know the eval evaluation context is more complex than that, but point stands) – David Mulder Mar 21 '14 at 19:06
• The point of the challenge was that you don't pass a string... -1 – Doorknob Mar 21 '14 at 20:31
• The point was not doing log("i:", i) ... I don't think it can't be done without ' or " in js ... you can make it smaller using console.log('log('+o+')'+eval(x)) but the output won't match the code line (who cares) – rafaelcastrocouto Mar 21 '14 at 22:34
• You can do it in a single line, I did it in node, how? By throwing an error, getting the stack, reading the file and extracting the line. Yep, kinda crazy :D. Additionally it might be possible using arguments.callee.caller.toString(), but I wasn't able to figure out which line is which when you have two logs. – David Mulder Mar 21 '14 at 23:34