53
\$\begingroup\$

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.

\$\endgroup\$
11

21 Answers 21

28
\$\begingroup\$

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!"
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Somewhere I saw this operator written as & and defined like this (&) = flip ($). \$\endgroup\$
    – swish
    Commented Jan 25, 2014 at 10:02
  • 6
    \$\begingroup\$ @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). \$\endgroup\$
    – lortabac
    Commented Jan 27, 2014 at 14:23
  • 1
    \$\begingroup\$ @swish you can save a character (and a brain-cycle) by using flip id \$\endgroup\$
    – Sean D
    Commented Aug 21, 2014 at 18:41
24
\$\begingroup\$

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?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Joey Adams
    Commented Feb 21, 2011 at 4:03
22
\$\begingroup\$

#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 ! {
#d`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;
    _

_
\$\endgroup\$
1
  • 7
    \$\begingroup\$ I was scrolling through the second block, and my only thought was "...down the rabbit hole." \$\endgroup\$ Commented Sep 14, 2014 at 11:13
18
\$\begingroup\$

Foreach in C

Iterate arrays (works for static arrays, not ones, received through pointer)

//syntactic beauty
#define in ,    

//syntactic beauty's helper macro
#define foreach(a) _foreach(a)

//the real foreach macro
#define _foreach(e,arr)\
typeof (&arr[0]) e;\
for (e=&arr[0];e!=&arr[sizeof(arr)/sizeof(arr[0])];e++)

To test it:

int int_arr[3]={10,20,30};    
char *strings[]={"Hello","World","Foreach","Test"};

foreach (num in int_arr) {
        printf ("num=%d\n",*num);
}

foreach (str in strings) {
        printf ("str=%s\n",*str);
}

result:

num=10
num=20
num=30
str=Hello
str=World
str=Foreach
str=Test
\$\endgroup\$
17
\$\begingroup\$

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).

\$\endgroup\$
16
\$\begingroup\$

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")))
\$\endgroup\$
14
\$\begingroup\$

"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!
\$\endgroup\$
1
12
\$\begingroup\$

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);
}
\$\endgroup\$
4
  • \$\begingroup\$ 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. \$\endgroup\$
    – Joey
    Commented Feb 21, 2011 at 9:25
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Feb 21, 2011 at 11:42
  • \$\begingroup\$ The C preprocessor adds extra garbage to the output, so your example wouldn't work as expected \$\endgroup\$ Commented Feb 25, 2011 at 9:17
  • 1
    \$\begingroup\$ A grep -v ^# whould fix that. I guess this is enough for this question :-) \$\endgroup\$ Commented Mar 1, 2011 at 18:57
9
\$\begingroup\$

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 guards 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 guard 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
\$\endgroup\$
3
  • \$\begingroup\$ 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. \$\endgroup\$
    – Joey Adams
    Commented Mar 5, 2011 at 22:15
  • \$\begingroup\$ 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. \$\endgroup\$
    – zbanks
    Commented Mar 5, 2011 at 23:34
  • \$\begingroup\$ This is not a code golf challenge; you can be more verbose (and readable) if you want! :) \$\endgroup\$
    – ReyCharles
    Commented Sep 16, 2014 at 19:20
7
\$\begingroup\$

Coroutine

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

Coroutines in C by Simon Tatham

\$\endgroup\$
7
\$\begingroup\$

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
\$\endgroup\$
7
\$\begingroup\$

Make C simpler

This code allows you to write C programs that kind of resemble a scripting language a bit more. It features keywords such as 'var', 'is', 'string', 'plus', 'equal' and several others. It works through a lot of define statements.

// pretty.c

#include<stdio.h>

#define function int
#define var int
#define is =
#define then {
#define do {
#define does {
#define end }
#define equal ==
#define notequal !=
#define greater >
#define less <
#define greaterequal >=
#define lessequal <=
#define display printf
#define otherwise }else{
#define increase ++
#define decrease --
#define plus +
#define minus -
#define times *
#define divide /
#define character char
#define string char*
#define integer int

This allows you to write code like:

/*
Preprocessor abuse, Yay!
*/

#include "pretty.c"

function main() does
    var myVar is 1;
    if(myVar greater 2)then
        display("Yep\n");
    otherwise
        display("Nope\n");
    end

    for(var i is 0; i less 10; i increase)do
        display("Loop: %d\n", i);
    end

    string myString = "Hello";
    display(myString);
end

The above gets expanded to:

int main() {
    int myVar = 1;
    if(myVar > 2){
        printf("Yep\n");
    }else{
        printf("Nope\n");
    }

    for(int i = 0; i < 10; i ++){
        printf("Loop: %d\n", i);
    }

    char* myString = "Hello";
    printf(myString);
}

Probably not overly useful but I found it quite interesting that you could essentially create an entire programming language through a bunch of #defines.

\$\endgroup\$
2
  • \$\begingroup\$ That looks like a Javascript/Ruby mashup... \$\endgroup\$
    – Beta Decay
    Commented Sep 14, 2014 at 10:40
  • \$\begingroup\$ There's pretty much no upper limit to this - with complex enough #defines, you can even give your language things like exception handling and garbage collection while still keeping the fundamental C layer underneath. \$\endgroup\$ Commented Oct 12, 2014 at 3:26
7
\$\begingroup\$

Multiline strings in javascript

in this elaborate syntax for multiline strings, every multiline string will be preceded with (function(){/* and a newline, and followed by a newline and */}+'').split('\n').slice(1,-1).join('\n').

using this amazing, intuitive syntax, we can finally use multiline strings:

var string = (function(){/*
THIS IS A MULTILINE STRING
HOORAY!!!
*/}+'').split('\n').slice(1,-1).join('\n');

console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!

for people who don't like our simple syntax, we have a compiler to our fabulous new language:

function compile(code)
{
    return code.replace("#{", "(function(){/*").replace("}#", "*/}+'').split('\n').slice(1,-1).join('\n')")
}

the same example, in the compiled-language version:

var string = #{
THIS IS A MULTILINE STRING
HOORAY!!!
}#;
console.log(string) // THIS IS A MULTILINE STRING
                    // HOORAY!!!
\$\endgroup\$
2
  • 1
    \$\begingroup\$ For some reason I can't put */ in my multiline strings. This is super annoying when including regexps in the strings! \$\endgroup\$
    – FireFly
    Commented Nov 14, 2014 at 14:50
  • \$\begingroup\$ @FireFly Actually, i think this still works. The syntex highlightening becomes weird though. \$\endgroup\$ Commented Nov 15, 2014 at 8:30
6
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ And it's just definitions in a dictionary, so you can use almost any type for the labels. \$\endgroup\$ Commented Jan 22, 2014 at 6:10
  • \$\begingroup\$ You can also do absolute jumps with currentfile <pos> setfileposition, counting bytes from the start of the file. \$\endgroup\$ Commented Feb 17, 2014 at 6:45
6
\$\begingroup\$

Sliceable List in C# (like Python)

I always enjoyed python's slice notation and wish it was available in C#

Usage:

SliceList<int> list = new SliceList<int>() { 5, 6, 2, 3, 1, 6 };
var a = list["-1"];     // Grab the last element (6)
var b = list["-2:"];    // Grab the last two elements (1,6)
var c = list[":-2"];    // Grab all but the last two elements (5,6,2,3)
var d = list["::-1"];   // Reverse the list (6,1,3,2,6,5)
var e = list["::2"];    // Grab every second item (5,2,1)

Code, far from error proof:

public class SliceList<T> : List<T>
{
    public object this[string slice]
    {
        get
        {
            if (string.IsNullOrWhiteSpace(slice))
                return this.ToList();
            int[] values = { 0, Count, 1 };
            string[] data = slice.Split(':');
            for(int i = 0; i < data.Length; i++)
            {
                if (string.IsNullOrEmpty(data[i])) continue;
                int value;
                int.TryParse(data[i], out value);
                if(value < 0 && i < 2)
                    value += Count;
                values[i] = value;
            }
            if (data.Length == 1)
                return this[values[0]];
            int start = Math.Min(values[0], values[1]);
            int stop = Math.Max(values[0], values[1]);
            int step = values[2];
            int sign = Math.Sign(step);
            if (sign < 0)
            {
                var temp = start;
                start = stop-1;
                stop = temp-1;
            }

            SliceList<T> newList = new SliceList<T>();
            for (int i = start; i != stop; i += step)
                newList.Add(this[i]);

            return newList;
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I requested slicing a long time ago to be included in .NET, it's still simply ignored :( \$\endgroup\$
    – Ray
    Commented Sep 23, 2014 at 11:53
5
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

Symbol#to_proc with arguments in Ruby

Symbol#to_proc is probably one of my favorite tricks for writing really succinct Ruby code. Suppose you have

nums = [1, 2, 3, 4]
text = %w(this is a test)

and you want to convert the contents of nums and text to Floats and uppercase words, respectively. Symbol#to_proc allows you to shorten code like this:

nums.map { |num| num.to_f }
text.map { |word| word.upcase }

to this:

nums.map(&:to_f)
text.map(&:upcase)

Awesome! But what if we want to raise every element in nums to the ith power, or replace every occurrence of s with * in text? Is there any way to shorten code like this?

nums.map { |num| num ** 1i }
nums.map { |word| word.gsub('s', '*') }

Alas, there's no easy way to pass arguments when using Symbol#to_proc. I've seen it done multiple ways, but probably two of the most clever and usable involve monkey-patching the Symbol class [1, 2]. I'll illustrate the first way below.

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

Now you can do things like:

nums.map(&:**.with(1i))
text.map(&:gsub.with('s', '*'))
nums.take_while(&:<.with(3))
text.delete_if(&:[].with('is'))
\$\endgroup\$
3
\$\begingroup\$

JavaScript foreach

var arr = ["Seattle", "WA", "New York", "NY", "Chicago", "IL"];

function foreach(fn, arr) {
  var s = fn.toString();
  var args = s.substring(s.indexOf('(')+1,s.indexOf(')')).split(",");
  var argsLen = args.length;
  var len = arr.length;
  for (var i = 0; i < len; i+=argsLen) {
    var part = arr.slice(i, i+argsLen);
    fn.apply(undefined, part);
  }
}

foreach (function(city, state) {
  console.log(city + ', ' + state);
}, arr);

Output

Seattle, WA
New York, NY
Chicago, IL

Alternate syntax, more like Tcl.

// Tcl's foreach loop for javascript.
// Keys in loop are prefixed with "this".
function tclForeach(keys, values, fn) {
  var obj={}, klen=keys.length, vlen=values.length, j, i;
  for (i=0, klen=keys.length; i < klen; i++) obj[keys[i]]=null;
  for(i = 0; i < vlen; i+=klen) {
    for(j=klen; j--;) obj[keys[j]] = values[i+j];
    fn.apply(obj);
  }
}

tclForeach(["city","state"], arr, function() {
  console.log(this.city + ', ' + this.state);
});
\$\endgroup\$
2
  • \$\begingroup\$ This isn't a plain foreach, but is more interesting. It inspects the argument list of the consuming function. You could go further with this trick and do really cool things. \$\endgroup\$
    – Joey Adams
    Commented Sep 22, 2014 at 13:14
  • 1
    \$\begingroup\$ I was going for a Tcl style foreach. I've added a slightly different approach that's more like Tcl. \$\endgroup\$
    – wolfhammer
    Commented Sep 22, 2014 at 23:02
2
\$\begingroup\$

Gotos in Haskell

the basic idea is that gotos can be partially simulated using the last statement in do-notations. for example:

main = do
  loop:
  print 3
  goto loop

is equivalent to

main = do
  loop
loop = do
  print 3
  loop

because execution will jump to the last statement, it is optimal to express gotos.

because the way it is done, gotos only jumps when they are at the do block of a toplevel definition directly. it is actually "call x and ignore the rest of the lexically seen statements" rather than "all x and ignore the rest of the statements", like a real goto.

the biggest problem is that when there is no way to leave execution from the middle of an IO action - even return doesn't; return does nothing when it isn't the last statement.

this overcomes this by capturing the rest of the statements by another do block.

goto loop
print 3

becomes

const loop $ do
print 3

the print 3 statement is captured by the do block, so loop becomes the last statement.

this transformation also supports variables being present at the scope of the actions. this is done by remembering the variables which are in scope, and passing them into the actions. for example:

printer r = do
  loop:
  putStrLn r
  goto loop
  print "this isn't executed"

this simply translates into:

printer r = do
  loop r
loop = do
  putStrLn r
  const (loop r) $ do
  print "this isn't executed"

some notes:

also, a return undefined statement is added to ensure the capturing do block is not empty.

because sometimes there is type ambiguity in the capturing do block, instead of const we use asTypeOf, which is the same as const but requires both its parameters to have the same type.

the actual implementation (in javascript):

function makeGoto(code)
{
    var vars = [] // the known variables
    
    // add the arguments to the functions to scope
    code.split('\n')[0].split('=')[0].split(' ').slice(1).forEach(function(varname){vars.push(varname)})
    return code.replace(/([ \t]*)([a-zA-Z]+):|([ \t]*)goto[ \t]+([a-zA-Z]+)|[ \t]+([a-zA-Z]+)[ \t]*<-/gm, function match(match, labelSpaces, label, gotoSpaces, goto, x)
        {
            if (label != undefined)
                return labelSpaces+label+" "+vars.join(' ')+"\n"+label+" "+vars.join(' ')+"=do ";
            else if(goto != undefined)
                return gotoSpaces+"asTypeOf("+goto+" "+vars.join(' ')+")$do\n"+gotoSpaces+"return undefined";
            else
            {
                vars.push(x);
                return match
            }
        })
}

an exampe:

main = do
    putSrtLn "a"
    goto label
    putStrLn "b"
    label:
    putStrLn "c"

becomes:

main = do
    putStrLn "a"
    asTypeOf(label )$do
    return undefined
    putStrLn "b"
    label 
label =do 
    putStrLn "c"

output:

a
c
\$\endgroup\$
1
  • \$\begingroup\$ It's worth clarifying that return in Haskell is a regular function, and unrelated to the keyword in C/etc. \$\endgroup\$
    – FireFly
    Commented Nov 14, 2014 at 12:51
1
\$\begingroup\$

Python Goto

goto.py

import sys, re
globals_ = globals()
def setglobals(g):
    global globals_
    globals_ = g
def goto(l):
    global globals_ 
    with open(sys.argv[0], "rb") as f:    
        data = f.read()
        data_ = data.split('\n')
    if isinstance(l, int):
        l-=1 if l > 0 else 0
    elif isinstance(l, str):
        r=re.search(r"^\s*(#{0}|(def|class)\s+{0})".format(l), data, re.MULTILINE)
        l=len(data_)-(data[r.start():].count("\n")) if r else len(data_)
    if 0 < l < len(data_) or 0 < (l*-1) <= len(data_):
        exec("".join(data_[l:]),globals_)
        sys.exit(1)

Usage

setglobals(globals()) #Set the globals to be used in exec to this file's globals (if imports or other variables are needed)
goto(8) #Goto line 8
goto(-8)#Goto 8th last line
goto("label")#Goto first occurrence of #label
goto("funcName")#Goto definition of funcName
goto("className")#Goto definition of className

Sample Test Case

import goto, sys
goto.goto(-1)
sys.exit(-1)

print "Asdf"

Sample Test Case Output

Asdf

Just a little fun with exec(). Can raise a maximum recursion depth error if not used properly.

\$\endgroup\$
-1
\$\begingroup\$

//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

\$\endgroup\$
3
  • \$\begingroup\$ @user2509848: This thread isn't tagged code golf. \$\endgroup\$
    – Joey Adams
    Commented Mar 3, 2014 at 7:18
  • \$\begingroup\$ What you posted requires script tag around it. Then where exactly is the new feature? \$\endgroup\$
    – manatwork
    Commented Mar 3, 2014 at 10:38
  • \$\begingroup\$ @JoeyAdams Oops, sorry. \$\endgroup\$
    – user10766
    Commented Mar 3, 2014 at 16:12

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