UP | HOME

Support via Liberapay

Babel: Language Compatability

Overview

This page looks at how consistent various languages are in babel. The goal is to document inconsistencies so they can be resolved or at least better understood.

Support for Common Headers

language :results value :results output default :results :prologue / :epilogue
C no yes output yes
java yes yes output no
python yes yes value yes
elisp yes yes value yes
shell yes yes output yes

Default Behaviors

language write source files to
C tempdir
java :dir else tempdir
python tempdir
elisp no tempfiles
shell no tempfiles

Variables

Summary

language int double string singleton list int list double list string list int table double table string table
C error error error error 2d string list 2d string list 2d list expected expected expected
java error error error error 2d string list 2d string list 2d list expected expected expected
python variant1 variant1 variant1 variant1 2d string list 2d string list 2d list expected expected expected
elisp variant1 variant1 variant1 error 2d string list 2d string list 2d list expected expected expected
shell variant1 variant1 variant1 expected list of strings n/a expected n/a n/a n/a

For tables, values are passed to code blocks in two dimensional arrays or lists with item types (ints, doubles, or strings) that match the data. Lists are passed as two dimensional arrays as if they are tables with one column of data, and all values are passed as strings. Only shell passes a list as a single dimentional array.

More details on how this can cause confusion in Round Trip.

Shell doesn't support doubles or multidimensional arrays, so those cases don't apply.

Callouts

  1. should ints and doubles be passed as strings?
  2. should lists be passed as 2d lists tables?
  3. should :results output require raw to produce an org list?
  4. should items include the trailing endline?
  5. why aren't singleton lists passed as lists?

Single Item

int

The following examples use this data:

#+name: int-item-data
10

Each example just outputs the given number surrounded in single quotes. This is the expected response:

#+RESULTS:
: '10'

Some languages return this instead:

#+RESULTS:
: '10
: '
  • C
    #+begin_src C :results output :var item=int-item-data
    printf("'%s'", item);
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and C doesn't allow multiline string literals.

  • java
    #+begin_src java :results output :var item=int-item-data
    System.out.println(String.format("'%s'", item));
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and java doesn't allow multiline string literals.

  • python
    #+begin_src python :results output :var item=int-item-data
    print("'{}'".format(item))
    #+end_src
    
  • elisp
    #+begin_src elisp :results output :var item=int-item-data
    (princ (format "'%s'" item))
    #+end_src
    
  • shell
    #+begin_src sh :results output :var item=int-item-data
    echo "'$item'"
    #+end_src
    

double

The following examples use this data:

#+name: double-item-data
10.1

Each example just outputs the given number surrounded in single quotes. This is the expected response:

#+RESULTS:
: '10.1'

Some languages return this instead:

#+RESULTS:
: '10.1
: '
  • C
    #+begin_src C :results output :var item=double-item-data
    printf("'%s'", item);
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and C doesn't allow multiline string literals.

  • java
    #+begin_src java :results output :var item=double-item-data
    System.out.println(String.format("'%s'", item));
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and java doesn't allow multiline string literals.

  • python
    #+begin_src python :results output :var item=double-item-data
    print("'{}'".format(item))
    #+end_src
    
  • elisp
    #+begin_src elisp :results output :var item=double-item-data
    (princ (format "'%s'" item))
    #+end_src
    
  • shell
    #+begin_src sh :results output :var item=double-item-data
    echo "'$item'"
    #+end_src
    

string

The following examples use this data:

#+name: string-item-data
ten

Each example just outputs the given number surrounded in single quotes. This is the expected response:

#+RESULTS:
: 'ten'

Some languages return this instead:

#+RESULTS:
: 'ten
: '
  • C
    #+begin_src C :results output :var item=string-item-data
    printf("'%s'", item);
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and C doesn't allow multiline string literals.

  • java
    #+begin_src java :results output :var item=string-item-data
    System.out.println(String.format("'%s'", item));
    #+end_src
    

    This does not compile because the variable value includes the trailing endline and java doesn't allow multiline string literals.

  • python
    #+begin_src python :results output :var item=string-item-data
    print("'{}'".format(item))
    #+end_src
    
  • elisp
    #+begin_src elisp :results output :var item=string-item-data
    (princ (format "'%s'" item))
    #+end_src
    
  • shell
    #+begin_src sh :results output :var item=string-item-data
    echo "'$item'"
    #+end_src
    

List

List of ints

The following examples use this data:

#+name: int-list-data
- 1
- 2
- 3

All examples compute the sum of the numbers in the list. Output should look like:

#+RESULTS:
: 6
  • C
    #+begin_src C :results output :var items=int-list-data
    int sum = 0;
    for (int ii=0; ii<items_rows; ii++) {
        sum += atoi(items[ii][0]);
    }
    printf("%d", sum);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=int-list-data
    import java.util.stream.Collectors;
    return items.stream()
        .collect(Collectors.summingInt(x -> Integer.parseInt(x.get(0))));
    #+end_src
    
  • python
    #+begin_src python :var items=int-list-data
    return sum([int(x[0]) for x in items])
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=int-list-data
    (apply '+ (mapcar (lambda (x) (string-to-number (car x)))
                      items))
    #+end_src
    
  • shell
    #+begin_src sh :var items=int-list-data
    sum=0
    for item in $items; do
        sum=$(($sum + $item))
    done
    echo $sum
    #+end_src
    

List of doubles

The following examples use this data

#+name: double-list-data
- 1.1
- 2.2
- 3.3

All examples compute the sum of the numbers in the list. Output should look like:

#+RESULTS:
: 6.6
  • C
    #+begin_src C :var items=double-list-data :includes <stdlib.h>
    double sum = 0;
    for (int ii=0; ii<items_rows; ii++) {
        sum += atof(items[ii][0]);
    }
    printf("%lf", sum);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=double-list-data
    import java.util.stream.Collectors;
    return items.stream()
        .collect(Collectors.summingDouble(x -> Double.parseDouble(x.get(0))));
    #+end_src
    
  • python
    #+begin_src python :var items=double-list-data
    return sum([float(x[0]) for x in items])
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=double-list-data
    (apply '+ (mapcar (lambda (x) (string-to-number (car x)))
                      items))
    #+end_src
    
  • shell

    Shell doesn't support doubles.

List of strings

The following examples use this data:

#+name: string-list-data
- a
- b
- c

Each example conncatenates the input into a space delimited list. Output looks like:

#+RESULTS:
: a b c
  • C
    #+begin_src C :results output :var items=string-list-data :include <string.h>
    char ret[8];
    memset(ret, 0, 8);
    for (int ii=0; ii<items_rows; ii++) {
        strcat(ret, " ");
        strcat(ret, items[ii][0]);
    }
    printf("%s", ret);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=string-list-data
    import java.util.stream.Collectors;
    return items.stream()
        .map(x -> x.get(0))
        .collect(Collectors.joining(" "));
    #+end_src
    
  • python
    #+begin_src python :var items=string-list-data
    return " ".join([x[0] for x in items])
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=string-list-data
    (mapconcat #'car items " ")
    #+end_src
    
  • shell
    #+begin_src sh :var items=string-list-data
    ret=""
    for item in $items; do
        ret="$ret $item"
    done
    echo $ret
    #+end_src
    

Singleton List

There is inconsistent behavior between lists of one vs many items. See Trimming a List to One Item for details.

The following examples use this data:

#+name: single-list-data
- one

Each source block just iterates over the input list, printing each value. Expected output is:

#+RESULTS:
: one

Some languages give this result:

#+RESULTS:
: o
: n
: e
  • C
    #+begin_src C :results output :var items=single-list-data[,0] :include <string.h>
    for (int ii=0; ii<items_cols; ii++) {
        printf("%s\n", items[ii]);
    }
    #+end_src
    

    This doesn't compile since items is passed as a char* instead of char*[].

  • java
    #+begin_src java :var items=single-list-data[,0]
    for (String item : items)
       System.out.println(item);
    #+end_src
    

    This doesn't compile since items is passed as a String instead of String[].

  • python
    #+begin_src python :results output :var items=single-list-data[,0]
    for item in items:
        print(item)
    #+end_src
    
  • elisp
    #+begin_src elisp :results output :var items=single-list-data[,0]
    (dolist (item items)
      (princ (format "%s\n" item)))
    #+end_src
    

    This fails with a type error because items is passed as a string instead of a list.

  • shell
    #+begin_src sh :var items=single-list-data[,0]
    for item in $items; do
        echo $item
    done
    #+end_src
    

Table

Table of ints

The following source blocks operate on this table:

#+name: int-table-data
| 1 | 2 |
| 3 | 4 |

Each source block sums the values found in the table. The output show look like:

#+RESULTS:
: 10
  • C
    #+begin_src C :var items=int-table-data
    int sum = 0;
    for (int ii=0; ii<items_rows; ii++) {
        for (int jj=0; jj<items_cols; jj++) {
            sum += items[ii][jj];
        }
     }
    printf("%d", sum);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=int-table-data
    int sum = 0;
    for (List<Integer> row : items) {
        for (Integer col : row) {
            sum += col;
        }
    }
    return sum;
    #+end_src
    
  • python
    #+begin_src python :var items=int-table-data
    sum = 0
    for row in items:
        for col in row:
            sum += col
    return sum
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=int-table-data
    (apply '+ (mapcar (lambda (x) (apply '+ x)) items))
    #+end_src
    
  • shell

    The table becomes an associated list instead of a 2d array. Bash doesn't support multidimensional arrays.

Table of doubles

The following source blocks operate on this table:

#+name: double-table-data
| 1.1 | 2.3 |
| 3.1 | 4.3 |

Each source block sums the values found in the table. The output show look like:

#+RESULTS:
: 10.8
  • C
    #+begin_src C :var items=double-table-data
    double sum = 0;
    for (int ii=0; ii<items_rows; ii++) {
        for (int jj=0; jj<items_cols; jj++) {
            sum += items[ii][jj];
        }
     }
    printf("%lf", sum);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=double-table-data
    double sum = 0;
    for (List<Double> row : items) {
        for (Double col : row) {
            sum += col;
        }
    }
    return sum;
    #+end_src
    
  • python
    #+begin_src python :var items=double-table-data
    sum = 0
    for row in items:
        for col in row:
            sum += col
    return sum
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=double-table-data
    (apply '+ (mapcar (lambda (x) (apply '+ x)) items))
    #+end_src
    
  • shell

    The table becomes an associated list instead of a 2d array. Bash doesn't support multidimensional arrays.

Table of strings

The following source blocks operate on this table:

#+name: string-table-data
| a | b |
| c | d |

concatenates the strings found in the table. The output show look like:

#+RESULTS:
: a b c d
  • C
    #+begin_src C :results output :var items=string-table-data :includes <string.h>
    char ret[8];
    memset(ret, 0, 8);
    for (int ii=0; ii<items_rows; ii++) {
        for (int jj=0; jj<items_cols; jj++) {
            strcat(ret, " ");
            strcat(ret, items[ii][jj]);
        }
     }
    printf("%s", ret);
    #+end_src
    
  • java
    #+begin_src java :results value :var items=string-table-data
    import java.util.stream.Collectors;
    return items.stream()
        .map(x -> String.join(" ", x))
        .collect(Collectors.joining(" "));
    #+end_src
    
  • python
    #+begin_src python :var items=string-table-data
    return " ".join([" ".join(x) for x in items])
    #+end_src
    
  • elisp
    #+begin_src elisp :var items=string-table-data
    (mapconcat (lambda (x) (mapconcat #'identity x " "))
               items " ")
    #+end_src
    
  • shell

    The table becomes an associated list instead of a 2d array. Bash doesn't support multidimensional arrays.

Results

Summary

language return list output list return table output table
C no support expected (w/ raw) no support expected
java expected expected (w/ raw) expected variant1
python expected expected (w/ raw) expected variant1
elisp expected expected (w/ raw) expected variant1
shell expected expected (w/ raw) expected expected

There is consistent behavior across languages for :results value but there are some inconsistencies with :results output.

My expectation is that writing rows of comma separated values should result in a table, but in some cases the :results raw is required for this to work and in other cases that is not enough.

Callouts

  1. Can C support :results value?
  2. should :results output require raw and write vertical bars to produce an org table?

List

When we return a list from a source code block, we want it to look like an org list.

#+RESULTS:
- one
- two

:results value

The following examples use :results value list.

  • C

    C has no support for :results value.

  • java
    #+begin_src java :results value list
      String[] ret = {"one", "two"};
      return ret;
    #+end_src
    
  • python
    #+begin_src python :python python3 :results value list
    return ("one", "two")
    #+end_src
    
  • elisp
    #+begin_src elisp :results value list
    '("one" "two")
    #+end_src
    

:results output

The following examples use :results output raw list. These have to use raw in order to work.

  • C
    #+begin_src C :results output raw list
    printf("one\n");
    printf("two\n");
    #+end_src
    
  • java
    #+begin_src java :results output raw list
    System.out.println("one");
    System.out.println("two");
    #+end_src
    
  • python
    #+begin_src python :python python3 :results output raw list
    print("one")
    print("two")
    #+end_src
    
  • elisp
    #+begin_src elisp :results output raw list
      (princ "one\n")
      (princ "two")
    #+end_src
    
  • shell
    #+begin_src sh :results output raw list
    echo "one"
    echo "two"
    #+end_src
    

Table

When we return a table from a source code block, we want it to look like an org table.

#+RESULTS:
| one   | two  |
| three | four |

Some languages return this instead.

#+RESULTS:
: one, two
: three, four

:results value

The following examples use :results value table.

  • C

    C has no support for :results value.

  • java
    #+begin_src java :results value table
      String [][] ret = {{"one","two"}, {"three", "four"}};
      return ret;
    #+end_src
    
  • python
    #+begin_src python :python python3 :results value table
    return (("one", "two"), ("three", "four"))
    #+end_src
    
  • elisp
    #+begin_src elisp :results value table
    '(("one" "two") ("three" "four"))
    #+end_src
    

:results output

The following examples use :results output table.

  • C
    #+begin_src C :results output table
    printf("one, two\n");
    printf("three, four\n");
    #+end_src
    
  • java
    #+begin_src java :results output table
    System.out.println("one, two");
    System.out.println("three, four");
    #+end_src
    

    that fails but this "raw table" output works:

    #+begin_src java :results output raw table
    System.out.println("|one| two");
    System.out.println("|three| four");
    #+end_src
    
  • python
    #+begin_src python :python python3 :results output table
      print("one, two")
      print("three, four")
    #+end_src
    

    doesn't work but raw table works

  • elisp
    #+begin_src elisp :results output table
      (princ "one, two\n")
      (princ "three, four")
    #+end_src
    

    doesn't work but raw table works

  • shell
    #+begin_src sh :results output table
    echo "one, two\nthree, four"
    #+end_src
    

Round Trip Between Source Blocks

If a source block (ret-list-source) returns a single dimensional array or list, it becomes an org list (ret-list-result).

#+name: ret-list-source
#+begin_src python :results list
return [1,2,3]
#+end_src
#+name: ret-list-result
#+RESULTS: ret-list-source
- 1
- 2
- 3

Then if another source block (read-list-result) accepts that list from the org buffer, it becomes a two dimensional table with one column.

#+name: read-list-result
#+begin_src python :var a=ret-list-result :results list
return a
#+end_src
#+RESULTS: read-list-result
- ("1")
- ("2")
- ("3")

But if a source block accepts the output directly from the ret-list-source, the input will be a single dimensional array.

#+name: read-list-direct
#+begin_src python :var a=ret-list-source :results list
return a
#+end_src
#+RESULTS: read-list-direct
- 1
- 2
- 3

Trimming a List to One Item

If a list contains more than one item, as in two-list-data, source blocks can access its items as a single dimensional list by indexing. Given the following data and source block:

#+name: two-list-data
- one
- two
#+begin_src python :results output :var items=one-list-data[,0]
for item in items:
    print (item)
#+end_src

The result, as expected, is:

#+RESULTS:
: one
: two

But if the list only contains one item, as in one-list-data, it is no longer passed to the source block as a list.

#+name: one-list-data
- one

Execution of the same source block as used above, but pointing at one-list-data, results in:

#+RESULTS:
: o
: n
: e

This can cause a problem if you trim your data to a single item in order to test a source block. Suddenly the source block is accepting a different data type.

Other Resources

Documentation from the orgmode.org/worg/ website (either in its HTML format or in its Org format) is licensed under the GNU Free Documentation License version 1.3 or later. The code examples and css stylesheets are licensed under the GNU General Public License v3 or later.