Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Your task is to tack on a feature to a programming language, either by implementing a very clever library, or by processing the input text and/or tweaking the compilation process.

Ideas:

  • Add PHP-style presentation interleaving to C (e.g. <?c printf("Hello,"); ?> world!).
  • Add a null coalescing operator to one of those languages that isn't C#.
  • Add macros to PHP.
  • Add goto to JavaScript.
  • Add pattern matching to language X.
  • Add namespace support to a language that doesn't have it.
  • Make C look like PHP.
  • Make Haskell look like Pascal.
  • ... (feel free to post ideas in the comment section)

Rules:

  • Bring something to the table. Don't just say "Template Haskell" to add metaprogramming facilities to Haskell. This isn't StackOverflow.
  • The entire implementation should fit in one screenful (not counting the example).
  • Do not host code on an external site specifically for this task.
  • The most impressive or surprising feature wins.

Don't worry about implementing the feature 100% correctly. Far from it! The main challenge is figuring out what you want to do and viciously cutting away details until your planned undertaking becomes feasible.

Example:

Add a lambda operator to the C programming language.

Initial approach:

Okay, I know I'd want to use libgc so my lambdas will solve the upward and downward funarg problems. I guess the first thing I'd need to do is write/find a parser for the C programming language, then I'd need to learn all about C's type system. I'd have to figure out how to make sense of it as far as types go. Would I need to implement type inference, or should I simply require that the formal parameter be typed as given? What about all those crazy features in C I don't know about yet?

It's quite clear that implementing lambda in C correctly would be a huge undertaking. Forget about correctness! Simplify, simplify.

Better:

Screw upward funargs, who needs 'em? I might be able to do something tricky with GNU C's nested functions and statement expressions. I wanted to show off an amazing syntactic transformation on C with terse, hacky code, but I won't even need a parser for this. That can wait for another day.

Result (requires GCC):

#include <stdio.h>
#include <stdlib.h>

#define lambda(d,e)({d;typeof(e)f(d){return(e);};f;})

#define map(F,A)({typeof(F)f=(F);typeof(*(A))*a=(A);({int i,l=((int*)(a))[-1]; \
typeof(f(*a))*r=(void*)((char*)malloc(sizeof(int)+l*sizeof(*r))+sizeof(int));  \
((int*)r)[-1]=l;for(i=0;i<l;i++)r[i]=f(a[i]);r;});})

#define convert_to(T) lambda(T x, x)
#define print(T, fmt) lambda(T x, printf(fmt "\n", x))

int main(void)
{
    int *array = 1 + (int[]){10, 1,2,3,4,5,6,7,8,9,10};
    map(print(int, "%d"), array);

    double *array2 = map(lambda(int x, (double)x * 0.5), array);
    map(print(double, "%.1f"), array2);

    long *array3 = map(convert_to(long), array2);
    map(print(long, "%ld"), array3);

    long product = 1;
    map(lambda(int x, product *= x), array);
    printf("product: %ld\n", product);

    return 0;
}

That was easy, wasn't it? I even threw in a map macro to make it useful and pretty.

share|improve this question
5  
I think Ken Thompson has us all beat: 0 bytes of code. –  dmckee Feb 20 '11 at 7:57
1  
I don't want to create a full answer, but I have added classes to GNU C, in case anyone is interested. –  Richard J. Ross III Oct 7 '13 at 3:09
1  
Not sure if this qualifies, but I've written a example of continuations in C. A little more than a screenfull, though. –  luser droog Jan 22 at 6:38
1  
My thanks to whoever resurrected this question; I have an excellent idea for my submission. –  Jonathan Van Matre Feb 27 at 20:49
 
@JonathanVanMatre: I look forward to seeing it. –  Joey Adams Feb 28 at 13:00
add comment

13 Answers

OOP syntax in Haskell

import Prelude hiding ((.))
a . b = b a

Objects can have properties:

[1,5,3,2].length -- 4
[1,5,3,2].maximum -- 5
'a'.succ -- 'b'

...and methods:

"Hello world!".take(5) -- "Hello"
"Hello world!".splitAt(2) -- ("He","llo world!")
"Hello world!".map(toUpper) -- "HELLO WORLD!"
share|improve this answer
1  
Somewhere I saw this operator written as & and defined like this (&) = flip ($). –  swish Jan 25 at 10:02
1  
@swish I didn't use & because it is the 'address-of' unary operator (the implementation of pointers in Haskell is left as an exercise for the reader). –  lortabac Jan 27 at 14:23
add comment

goto in JavaScript?

My first thought was a functional approach – to add a parameter to the function to indicate where execution should start, using that with a switch statement and an outer loop repeatedly calling the function on its own return value. Unfortunately, that would preclude the use of local variables, as they would lose their values with every goto.

I could use a with statement and move all variable declarations to the beginning of the function, but there had to be a better way. It eventually came to me to use JavaScript's exception handling. In fact, Joel Spolsky said, "I consider exceptions to be no better than "goto's..." – obviously a perfect fit.

The idea was to put an infinite loop inside a function, terminated only by a return statement or an uncaught exception. All gotos, treated as exceptions, would be caught within the loop to prevent its termination. Here is the result of that approach:

function rewriteGoTo(func) {
    var code = '(';
    code += func.toString()
        .replace(/^\s*(\w+)\s*:/gm, 'case "$1":')
        .replace('{', '{ var $_label = ""; function goTo(label) { $_label = label; throw goTo; } while(true) try { { switch($_label) { case "": ');
    code += '} return; } catch($_e) { if($_e !== goTo) throw $_e; } })';
    return code;
}

You can use it like this – even in ES5 strict mode – except in Internet Explorer (demo):

var test = eval(rewriteGoTo(function(before) {
    var i = 1;
    again: print(before + i);
    i = i + 1;
    if(i <= 10) goTo('again');
}));

[Internet Explorer, for some reason, fails to eval the code of an anonymous function, so one would have to give the function a name (before rewriting) and call it using that name. Of course, that would probably break strict mode's rules.]

This does not allow jumping to a statement located within a block (until such constructs as Duff's device become legal), but we can deal with that (another, self-executing rewritten function), right?

share|improve this answer
 
Sweet! Nice job keeping it simple. An interesting bit of trivia: if goto were implemented fully in JavaScript (to where you could use goto to jump out of any scope, even a function), it would imply support for continuations. –  Joey Adams Feb 21 '11 at 4:03
add comment

Add macros to PHP

We can just use the C preprocessor for this task.

A php script:

<?php

#define ERROR(str) trigger_error(#str, E_USER_ERROR)

function test() {
        ERROR(Oops);
}

Pipe it though cpp:

cpp < test.php

Result:

<?php

function test() {
 trigger_error("Oops", E_USER_ERROR);
}
share|improve this answer
 
Won't that break with PHP features that don't exist in C? Such as heredocs. Afair the C PP was pretty tightly tied to C's grammar. –  Joey Feb 21 '11 at 9:25
1  
I think the preprocessor only lexes the input without trying to make sense of it. An <<<HEREDOC is nothing more than 3 lower-than or left-shift and an identifier :-) This will do macro-substitution in heredoc strings, however. –  user300 Feb 21 '11 at 11:42
 
The C preprocessor adds extra garbage to the output, so your example wouldn't work as expected –  Charlie Somerville Feb 25 '11 at 9:17
1  
A grep -v ^# whould fix that. I guess this is enough for this question :-) –  user300 Mar 1 '11 at 18:57
add comment

Pattern Matching Guards in Python

def pattern_match(n, s="__fns"):
 s=n+s;g=globals()
 def m(f):
  def a(*r):
   for f in g[s]:
    if reduce(lambda c,t:c and eval(t[1:],{},dict(zip(f.func_code.co_varnames,r))),filter(lambda x:x and x[0]is"|",map(lambda x:x.strip(),f.func_doc.split("\n")))): return f(*r)
  g[n]=a;g[s]=(g.get(s)or[])+[f]
  return a
 return m

The body of the function comes in at 288 characters.

Pattern Matching Guards allow you to use completely different functions depending on argument values. Although it can be easily emulated with a series of if statements, pattern matching can help separate sections of code, and it's a great excuse to do some crazy metaprogramming.

pattern_match is a decorator that creates a new function that implements pattern matching guards. The conditions for each "sub-function" given in each docstring on lines starting with a pipe (|). If all conditions evaluate truthily, that version of the function is run. Functions are tested in order until a match is found. Otherwise, None is returned.

An example will help clarify:

@pattern_match("test1")
def test1_a(a, b, c):
    """
    This pattern tests if a and c are positive

    | a > 0
    | c > 0
    """
    return a + b + c

@pattern_match("test1")
def test1_b(a, b, c):
    """
    This pattern only ensures b is positive

    | b > 0
    """
    return b + c

@pattern_match("test1")
def test1_c(a, b, c):
    """
    Final catchall

    | True
    """
    return 0


print test1(1,2,3) # (a) >>> 6
print test1(1,2,0) # (b) >>> 2
print test1(1,0,0) # (c) >>> 0
print test1(0,0,1) # (b) >>> 1
share|improve this answer
 
In Haskell, this is called guards, not pattern matching. In Haskell, pattern matching lets you say f [a,b,c] = ..., which not only tests the argument against a predicate, but it binds the respective variables upon successful match. This is still pretty cool, though. –  Joey Adams Mar 5 '11 at 22:15
 
D'oy! Thanks for correcting that! I was thinking about Haskell too, specifically focusing on defining a function with two different predicates (i.e. f (x:xs) = ... and f [] = ...). Somehow I convoluted guards into there, but that's where I took the | from. –  zbanks Mar 5 '11 at 23:34
add comment

Computed come-from in Common Lisp

I initially implemented come-from. But that wasn't good enough.

Inspired by the computed goto, I decided to implement computed come-from.

(defmacro computed-come-from-tagbody (&rest statements)
  (let ((has-comp-come-from nil)
        (comp-come-from-var nil)
        (start-tag (gensym))
        (end-tag (gensym)))

    (let ((current-tag start-tag)
          (come-froms (make-hash-table :test #'eq)))

      (let ((clauses '()))
        (loop for statement in statements do
             (if (symbolp statement)
                 (setf current-tag statement))

             (cond
               ((and (consp statement)
                     (eql 'come-from (car statement)))

                (setf has-comp-come-from t)
                (setf (gethash (cadr statement) come-froms) current-tag))
               (t (push statement clauses))))


        (if (not has-comp-come-from)
            `(tagbody ,@(reverse clauses))
            (let ((res '())
                  (current-tag start-tag))
              (loop for clause in (reverse clauses) do
                   (cond
                     ((symbolp clause)
                      (push clause res)
                      (setf current-tag clause)
                      ;; check all vars for jumps
                      (push
                       `(progn ,@(loop for k being the hash-key of come-froms
                                    for v being the hash-value of come-froms collect
                                      `(when (eql ,k ,current-tag)
                                         (go ,v))))
                       res))
                     (t (push clause res))))
              `(macrolet ((come-from (idx)
                            (declare (ignore idx))
                            (error "Come-from cannot be used with another form.")))
                 (tagbody ,@(reverse res)))))))))

Examples of usage

(come-from x) ; whenever we're at the top of a labeled block and the value of x is equal to the label, jump back to this point.

For each come-from declaration in the tagbody, it will check at each label if the come-from variable is equal to the current label, and if so, jump to the corresponding come-from declaration.

Greeter

(let ((x :repeat)
      (y :exit))
   (computed-come-from-tagbody
      :loop              ;; when x == :loop jump to :loop.  when y == :loop jump to :exit
      (come-from x)
      (format t "What is your name? ")
      (let ((name (read-line)))
         (terpri)
         (format t "Hello ~a~%" name)
         (print (string= name "exit"))
         (when (string= name "exit")
             (setf x nil
                   y :repeat)))
       :repeat           ;; when x = :repeat jump to loop, when y = :repeat jump to exit
       :exit             ;; when x = :exit jump to loop, when y = :exit jump to exit
       (come-from y)))

FizzBuzz

(let ((i 0)
      (x nil)
      (y nil))
   (computed-come-from-tagbody
       :loop
       (come-from x)
       (cond
         ((> i 100)  (setf x nil
                           y :end-iteration)) 
         (t (or (and (zerop (mod i 3)) (zerop (mod i 5)) (print "FizzBuzz"))
                (and (zerop (mod i 3)) (print "Fizz"))
                (and (zerop (mod i 5)) (print "Buzz"))
                (print i))  
            (incf i)
            (setf x :end-iteration)))
       :end-iteration
       :end
       (come-from y)
       (print "done")))
share|improve this answer
add comment

Properties in C

Tomasz Wegrzanowski implemented properties in plain C, by intentionally segfaulting the program when the property is accessed.

An object with a "property" is set up by creating a struct that crosses multiple pages, ensuring that the property's memory address lies in a different page from the real data members. The property's page is marked as no-access, guaranteeing that attempting to access the property will cause a segfault. A fault handler then figures out which property access caused the segfault, and calls the appropriate function to compute the property's value, which gets stored at the property's memory address.

The fault handler also marks the data page as read-only to ensure the computed value remains consistent; when you next try to write to a data member, that triggers a segfault, whose handler sets the data page as read-write and the property page as no-access (indicating that it needs to be recomputed).

share|improve this answer
add comment

#define in Java

I thought it would be fun to implement macros in Java.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * defines the use of #define. Usage:
 *
 * #def toReplaceCanHaveNoSpaces replacement can have extra spaces
 *
 * must be at the beginning of the line (excluding starting spaces or tabs)
 * 
 * @author Quincunx
 */
public class Define {

    public static void main(String[] args) {
        if (args.length != 1) {
            err("Please provide exactly 1 argument");
        }
        File source = new File(args[0]);
        if (!source.exists()) {
            err("Supplied filepath does not point to an existing file");
        }
        if (!getExtension(args[0]).equalsIgnoreCase(".java")) {
            err("Supplied file is not of type .java");
        }
        ArrayList<String> sourceData = new ArrayList<>();
        ArrayList<String[]> replacements = new ArrayList<>();
        try {
            BufferedReader read = new BufferedReader(new FileReader(source));
            String data;
            while ((data = read.readLine()) != null) {
                sourceData.add(data);
            }
            read.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
        for (int index = 0; index < sourceData.size(); index++) {
            String line = sourceData.get(index);
            line = line.replaceAll("\t", "    ");
            for (String[] e : replacements) {
                line = line.replace(e[0], e[1]);
            }

            if (line.trim().charAt(0) != '#') {
                sourceData.set(index, line);
                continue;
            }
            while (line.charAt(0) != '#') {
                line = line.substring(1);
            }
            int indexOf = line.indexOf(" ");
            String type = line.substring(1, indexOf);

            switch (type) {
                case "def":
                case "define":
                    String toReplace = line.substring(indexOf + 1, line.indexOf(" ", indexOf + 1));
                    replacements.add(new String[]{toReplace, line.substring(line.indexOf(":") + 1)});
                    break;
                default:
                    err("The source code contains a # in which there is no correct type");
            }
        }

        try {
            BufferedWriter write = new BufferedWriter(new FileWriter(source));
            for (String s : sourceData) {
                write.write(s);
                write.newLine();
            }
            write.close();
        } catch (IOException ex) {
            Logger.getLogger(Define.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void err(String message) {
        System.err.println(message);
        System.exit(1);
    }

    public static String getExtension(String filePath) {
        return filePath.substring(filePath.lastIndexOf("."));
    }

}

Sample usage (converts to previously posted code; let's make it weird):

#def @ o
#def ~ a
#def $ i
#def ` e
#d`f % m
#d`f ! {
#&`f & d
#&`f _ }
#&`f 2 (
#&`f 7 )
#&`f $%p@rt$@. $%p@rt j~v~.$@.
#&`f $%p@rtu. $%p@rt j~v~.ut$l.
#&`f ps publ$c st~t$c
#&`f Str Str$ng

$%p@[email protected]`r`&R`~&`r;
$%p@[email protected]`r`&Wr$t`r;
$%p@[email protected]$l`;
$%p@[email protected]$l`R`~&`r;
$%p@[email protected]$l`Wr$t`r;
$%p@[email protected]`pt$@n;
$%[email protected]~yL$st;
$%[email protected]@gg$ng.L`v`l;
$%[email protected]@gg$ng.L@gg`r;

#d`f L$st Arr~yL$st
#d`f l@g; L@gg`r.g`tL@gg`r2D`f$n`.cl~ss.g`tN~m`277.l@g2L`v`l.SEVERE, null, `x7;    

publ$c cl~ss D`f$n` !

    ps v@$d %ain2Str[] ~rgs7!
        $f 2~rgs.l`ngth != 17 !
            `rr2"Pl`~s` pr@v$&` `x~ctly 1 ~rgu%`nt"7;
        _
        F$l` squrc` = n`w F$l`2~rgs[0]7;
        $f 2!sourc`.`x$sts277 !
            `rr2"Suppli`& f$l`p~th &@`s n@t p@int t@ ~n `x$st$ng f$l`"7;
        _
        $f 2!g`tExt`ns$@n2~rgs[0]7.`qu~lsIgn@r`C~s`2".j~v~"77 !
            `rr2"Suppl$`& f$l` $s n@t @f typ` .j~v~"7;
        _
        L$st<Str> s@urceDat~ = n`w List<>27;
        L$st<Str[]> repl~cem`nts = n`w L$st<>27;
        try !
            Buff`r`&R`a&`r r`a& = new Buff`redRe~&`r2n`w F$l`R`~&`r2s@urc`77;
            Str &~t~;
            wh$l` 22&~t~ = r`~&.r`~&L$n`277 != null7 !
                s@urc`D~t~.~&&2&ata7;
            _
            re~&.cl@se27;
        _ c~tch 2IOExc`ption ex7 !
            log;
        _
        f@r 2$nt $n&`x = 0; $ndex < s@urc`D~t~.s$z`27; $nd`x++7 !
            Str l$n` = s@urc`D~ta.get2index7;
            line = line.r`pl~c`All2"\t", "    "7;
            for 2Str[] ` : r`pl~c`%`nts7 {
                line = line.r`pl~c`2`[0], e[1]7;
            _

            if 2l$ne.tr$%27.ch~rAt207 != '#'7 !
                sourc`D~t~.s`t2$n&`x, l$n`7;
                c@nt$nu`;
            _
            wh$l` 2line.ch~rAt207 != '#'7 !
                l$ne = l$ne.substr$ng217;
            _
            $nt in&`xOf = line.$n&`xOf2" "7;
            Str typ` = line.substring21, indexOf7;

            sw$tch 2type7 !
                c~s` "&`f":
                c~s` "def$n`":
                    str t@R`pl~c` = line.substring2indexOf + 1, line.indexOf2" ", indexOf + 177;
                    r`pl~c`%`nts.~&&2n`w s\Str[]!t@R`place, line.substring2line.indexOf2":"7 + 17_7;
                    br`~k;
                def~ult:
                    err2"Th` s@urc` c@&` c@nt~$ns ~ # $n wh$ch th`r` i$s n@ c@rr`ct typ`"7;
            _
        _

        try !
            Buff`r`&Wr$ter wr$te = new BufferedWriter2new F$l1Wr$t1r2s@urc177;
            for 2Str s : s@urceData7 !
                wr$te.write2s7;
                wr$te.n`wLin`27;
            _
            wr$t`.cl@s`27;
        _ c~tch 2IOExc`pt$@n `x7 !
            l@g;
        _
    _

    ps v@$& `rr2Str m`ss~g`7 !
        Syst`%.`rr.pr$ntln2message7;
        Syst`%.`x$t217;
    _

    ps Str g`tExt`nsi@n2Str fileP~th7 !
        r`turn f$lePath.substr$ng2f$l`P~th.l~stInd`xOf2"."77;
    _

_
share|improve this answer
add comment

Coroutine

I can't take credit for this, so i've marked it CW.

Coroutines in C by Simon Tatham

share|improve this answer
add comment

"Auto-strings" in Ruby

The code is quite simple:

def self.method_missing *a; a.join ' '; end

Now you can do

print This is an automatic string #=> This is an automatic string
print hooray #=> hooray

x = code golf
print This is + ' ' + x + '!' #=> This is code golf!
share|improve this answer
3  
wat –  undergroundmonorail Feb 27 at 14:23
add comment

Tcl

Tcl has no do ... while or do ... until so...

proc do {body op expr} {
    uplevel 1 $body
    switch -exact -- $op {
        while {
            while {[uplevel 1 [list expr $expr]} {
                uplevel 1 $body
            }
        }
        until {
            while {![uplevel 1 [list expr $expr]} {
                 uplevel 1 $body
            }
        }
    }
}

Example:

do {
    puts -nonewline "Are you sure? "
    flush stdout
    set result [gets stdin]
} while {[string is boolean -strict $result]}

uplevel executes a script in the callers scope.

share|improve this answer
add comment

Custom operators in Lua

Pogs cleverly abused operator overloading in Lua in order to allow custom infix operators to be defined. I've expanded this to support operator sectioning (partially applying an operator with either operand) and calling the resulting object as if it were a function.

---- implementation
function infix(f)
  local function g(self, x)
    return f(self[1] or x, self[2] or x)
  end

  local mt   = { __sub = g, __call = g }
  local self = {}
  return setmetatable(self,
           { __sub = function (lhs,rhs)
                       return rhs == self and setmetatable({ lhs, nil }, mt)
                                           or setmetatable({ nil, rhs }, mt)
                     end })
end

---- testing
local eq   = infix(function (a, b) return a == b end)
local ge   = infix(function (a, b) return a >= b end)

local comp = infix(function (a, b) return a < b and -1
                                       or a > b and  1
                                       or            0 end)

function filter(pred, xs)
  local res = {}
  for i=1,#xs do
    if pred(xs[i]) then table.insert(res, xs[i]) end
  end
  return res
end

print(1  -eq-  1)                                      --> true
print(1 -comp- 0)                                      --> 1
print((4 -ge)(1))                                      --> true
print(table.unpack(filter(ge- 0, {1,-4,3,2,-8,0})))    --> 1   3   2   0
share|improve this answer
add comment

Goto in PostScript

My first thought was that I'd have to muck about with the exec stack, so this false start digs up the continuation operator for stopped from ghostscript (or xpost).

/_stopped_mark
{countexecstack array execstack dup length 2 sub get}
stopped pop def 

But, it's simpler than that. Because file-position is the same for all duplicates of the file handle (setfileposition consumes its argument, so this is the only useful semantics for that function).

/LABELS 10 dict def 

/: { % n :  define label
    LABELS exch currentfile fileposition put 
} def 

/goto { % goto label
    currentfile exch LABELS exch get setfileposition
} def 

/x 0 def 

/here :
    /x x 1 add def 

    x 5 ne {
        /here goto
    } if

x =

It prints 5.

There are some limitations with the above. The jump is not immediate, but happens when the if-body returns to the top-level and the interpreter is again reading from the file (instead of reading from the array that contains the if-body). At that point, the file has been repositioned and the 'goto' takes effect.

share|improve this answer
 
And it's just definitions in a dictionary, so you can use almost any type for the labels. –  luser droog Jan 22 at 6:10
 
You can also do absolute jumps with currentfile <pos> setfileposition, counting bytes from the start of the file. –  luser droog Feb 17 at 6:45
add comment

//import javascript without especifically using the script tag in a HTML page

function i(u) {
  document.write("script src=\" + u + \"></script>");
}

i("http://www.mysite.com/myscript.js");

It's lame yeah I know. Length: 99

share|improve this answer
 
@user2509848: This thread isn't tagged code golf. –  Joey Adams 17 hours ago
 
What you posted requires script tag around it. Then where exactly is the new feature? –  manatwork 13 hours ago
 
@JoeyAdams Oops, sorry. –  hosch250 8 hours ago
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.