Sinister Scheme Sample Perplexes Python Porter

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


EditText of this page (last edited February 22, 2011) or FindPage with title or text search