#35 Odd behavior with delay/force and symbols

open
nobody
None
5
2013-05-07
2012-01-01
No

This works ("=>" denotes the prompt):

=> (define x (delay 5))
=> (force x)
=> (eqv? x 5)
#t

However, this doesn't (x and 'sym are not equal):

=> (define x (delay 'sym))
=> (force x)
=> (eqv? x 'sym)
#f

This is particularly odd because x evaluates to 'sum at the prompt.

Is this a bug in TinyScheme or a mistake on my side? From time to time I'm still confused with Scheme's evaluation model.

Discussion

  • Maximilian Claus

    It is getting more and more confusing:

    (define x (delay "Hello World"))

    (define (test) (begin (write (force x)) (test)))

    If I run "test", after a couple of seconds the beginning of the string "Hello World" changes to a couple of zeros. I was able to reproduce this behavior with every attempt to run this program.

    I wonder if this may be system-specific issue (OS X) and would be very much interested to see if it works on other systems as expected.

     
  • Maximilian Claus

    And promises seem to be broken with vectors as well. It looks like promises require a completely new implementation. I have looked into the source, but I'm not really getting what's going on there...

     
  • Maximilian Claus

    I identified the problem now and this is quite a severe bug in the GC/promise implementation:

    When a promise is forced, the promise cell is replaced by a copy of its result (the object is therefore duplicated). What can happen now is that the cell or its duplicate is no longer used and therefore not marked by the GC, which in case of a string for instance results in the finalization of that string, even if the other cell referencing the same string still lives!! Vectors are affected in a similar fashion and in general this breaks all objects which require some kind of finalization.

    I propose the following fix:

    Adding a special flag for a forced promise:

    #define T_FORCED_PROM      2048    /* 0000100000000000 */
    

    Modifying the promise handling code (l. 3728):

         case OP_FORCE:      /* force */
              sc->code = car(sc->args);
              if (is_promise(sc->code)) {
                   if(sc->code->_flag & T_FORCED_PROM)
                     s_return(sc,car(sc->code));
                   else {
                     /* Should change type to closure here */
                     s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
                     sc->args = sc->NIL;
                     s_goto(sc,OP_APPLY);
                   }
              } else {
                   s_return(sc,sc->code);
              }
    
         case OP_SAVE_FORCED:     /* Save forced value replacing promise */
              sc->code->_flag |= T_FORCED_PROM;
              car(sc->code) = sc->value;
              cdr(sc->code) = sc->NIL;
              s_return(sc,sc->value);
    

    This code is also conform with other Scheme implementations (to obtain a delayed value the promise needs to be forced every time).

    Given that I'm not very familiar with TinyScheme's idiom this is a bit of a hack by me and I'd be happy if somebody could implement this in a proper fashion.

     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks