Sinister Scheme Sample Perplexes Python Porter

last modified: February 22, 2011

translation challenge from PythonTranslator...

Evil grin. OK, what about the following Scheme code.

Scheme

;;; Pointers in Scheme
;;; Adding pointer arithmetic is left as an exercise to the reader
(define (make-pointer getter setter)
  (cons getter setter))

(define (pointer-ref ptr)
  ((car ptr)))

(define (pointer-set! ptr value)
  ((cdr ptr) value))

(define-syntax address
  (syntax-rules ()
     ((address var)
      (make-pointer
        (lambda () var)
        (lambda (value) (set! var value))))))

;;; A few examples
(define x 1)
(define px (address x))
(display (pointer-ref px))(newline)
(pointer-set! px 2)
(display (pointer-ref px))(newline)

Python

# Take a first cut.  

class Pointer:
    def __init__(self, var):
        self.var = var

    def set(self, val):
        self.var = val        

    def get(self):
        return self.var

x = 1
px = Pointer(x)
print px.get()
px.set(2)
print px.get()

# So far so good.  But then this breaks...

y = 10
py = Pointer(y)
py.set(20)
print y

# When we print y, it's still 10.  The problem is, 
# primitive types pass by value in Python.
# So let's try making an Integer object.

class Integer:
    def __init__(self, val):
        self.val = val

    def set(self, val):
        self.val = val

    def get(self):
        return self.val

# And we can add a level of indirection.

class Ptr:
    def __init__(self, var):
        self.var = var

    def set(self, val):
        self.var.set(val)

    def get(self):
        return self.var.get()

print 'Test #2'
y = Integer(10)
print y.get()
py = Ptr(y)
py.set(20)
print y.get()

# And that seems to work.  

-- SteveHowell


So pointer allows you to call get/set on anything that already has a get/set method? So what's the point? :-)


Yep, it's kind of pointless to implement a pointer scheme in a language like Python, which solves problems just fine without them. That's what made this particular challenge so sinister. Insidious, even. -- SteveHowell

Nevertheless, it is an interesting problem. I explore a RubyLanguage version on the SinisterSchemeSampleInRuby page. -- JimWeirich


For the interested, here is some background information on the original Scheme code. The method outlined here to simulate pointers in Scheme was used in an early C-to-Lisp compiler for the MIT Lisp machine. (The C compiler on the later commercial Lisp machine didn't use this trick; it generated machine-code for the Lisp machine directly, just like a conventional C compiler.) One can have more operations that just set and get; in particular, one can implement pointer arithmetic. For this, the limitation in the ANSI C standard that pointer arithmetic only works on pointers that point into the same array is essential.

The piece of memory that contains the value of a variable is called a location in Scheme. In effect, the above Scheme code makes locations available as first-class values. We call this process reification. Thus, the Scheme code implements reifiable locations, or locatives for short. Note that these locatives have unlimited extent, unlike C pointers, which have dynamic extent.

There was a Scheme dialect called T that made heavy use of locatives.

So now you know why C "pointers" should really by called "first-class reified locations with dynamic extent." ;-)

-- StephanHouben

I think I might know how to do arithmetic.

(def *heap* nil)
(define (malloc ()
    (def lexvar nil)
    (let (a (address lexvar)
        (set! *heap* (cons a *heap*))
        a)))

Then do heap manipulations. Can someone help with this?

...Oh, wait. I see...

(define (malloc (size)
    (if (= size 0)
        nil
        (cons nil (malloc (- size 1))))))
(define (ptr+ (aConsCell num)
     (if (= num 0)
         aConsCell
         (ptr+ (cdr aConsCell) (- num 1)))))

CategoryPython


Loading...